@@ -128,10 +128,6 @@ interface UnderlyingCall {
128128 * This is different from nextMessageToSend which tracks completion/acknowledgment.
129129 */
130130 highestSentMessageIndex : number ;
131- /**
132- * Tracks whether halfClose has been sent to this child call.
133- */
134- halfCloseSent : boolean ;
135131 startTime : Date ;
136132}
137133
@@ -705,7 +701,6 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
705701 call : child ,
706702 nextMessageToSend : 0 ,
707703 highestSentMessageIndex : - 1 ,
708- halfCloseSent : false ,
709704 startTime : new Date ( ) ,
710705 } ) ;
711706 const previousAttempts = this . attempts - 1 ;
@@ -771,11 +766,10 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
771766 this . maybeStartHedgingTimer ( ) ;
772767 }
773768
774- private handleChildWriteCompleted ( childIndex : number ) {
775- const childCall = this . underlyingCalls [ childIndex ] ;
776- const messageIndex = childCall . nextMessageToSend ;
769+ private handleChildWriteCompleted ( childIndex : number , messageIndex : number ) {
777770 this . getBufferEntry ( messageIndex ) . callback ?.( ) ;
778771 this . clearSentMessages ( ) ;
772+ const childCall = this . underlyingCalls [ childIndex ] ;
779773 childCall . nextMessageToSend += 1 ;
780774 this . sendNextChildMessage ( childIndex ) ;
781775 }
@@ -785,40 +779,38 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
785779 if ( childCall . state === 'COMPLETED' ) {
786780 return ;
787781 }
788- if ( this . getBufferEntry ( childCall . nextMessageToSend ) ) {
789- const bufferEntry = this . getBufferEntry ( childCall . nextMessageToSend ) ;
782+ const messageIndex = childCall . nextMessageToSend ;
783+ if ( this . getBufferEntry ( messageIndex ) ) {
784+ const bufferEntry = this . getBufferEntry ( messageIndex ) ;
790785 switch ( bufferEntry . entryType ) {
791786 case 'MESSAGE' :
792- childCall . highestSentMessageIndex = childCall . nextMessageToSend ;
793787 childCall . call . sendMessageWithContext (
794788 {
795789 callback : error => {
796790 // Ignore error
797- this . handleChildWriteCompleted ( childIndex ) ;
791+ this . handleChildWriteCompleted ( childIndex , messageIndex ) ;
798792 } ,
799793 } ,
800794 bufferEntry . message ! . message
801795 ) ;
796+ childCall . highestSentMessageIndex = messageIndex ;
802797 // Optimization: if the next entry is HALF_CLOSE, send it immediately
803798 // without waiting for the message callback. This is safe because the message
804799 // has already been passed to the underlying transport.
805- const nextEntry = this . getBufferEntry ( childCall . nextMessageToSend + 1 ) ;
806- if ( nextEntry . entryType === 'HALF_CLOSE' && ! childCall . halfCloseSent ) {
800+ const nextEntry = this . getBufferEntry ( messageIndex + 1 ) ;
801+ if ( nextEntry . entryType === 'HALF_CLOSE' ) {
807802 this . trace (
808803 'Sending halfClose immediately after message to child [' +
809804 childCall . call . getCallNumber ( ) +
810805 '] - optimizing for unary/final message'
811806 ) ;
812- childCall . halfCloseSent = true ;
807+ childCall . nextMessageToSend += 1 ;
813808 childCall . call . halfClose ( ) ;
814809 }
815810 break ;
816811 case 'HALF_CLOSE' :
817- if ( ! childCall . halfCloseSent ) {
818- childCall . nextMessageToSend += 1 ;
819- childCall . halfCloseSent = true ;
820- childCall . call . halfClose ( ) ;
821- }
812+ childCall . nextMessageToSend += 1 ;
813+ childCall . call . halfClose ( ) ;
822814 break ;
823815 case 'FREED' :
824816 // Should not be possible
@@ -847,16 +839,16 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
847839 call . state === 'ACTIVE' &&
848840 call . nextMessageToSend === messageIndex
849841 ) {
850- call . highestSentMessageIndex = messageIndex ;
851842 call . call . sendMessageWithContext (
852843 {
853844 callback : error => {
854845 // Ignore error
855- this . handleChildWriteCompleted ( callIndex ) ;
846+ this . handleChildWriteCompleted ( callIndex , messageIndex ) ;
856847 } ,
857848 } ,
858849 message
859850 ) ;
851+ call . highestSentMessageIndex = messageIndex ;
860852 }
861853 }
862854 } else {
@@ -873,7 +865,7 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
873865 {
874866 callback : error => {
875867 // Ignore error
876- this . handleChildWriteCompleted ( this . committedCallIndex ! ) ;
868+ this . handleChildWriteCompleted ( this . committedCallIndex ! , messageIndex ) ;
877869 } ,
878870 } ,
879871 message
@@ -898,19 +890,18 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
898890 allocated : false ,
899891 } ) ;
900892 for ( const call of this . underlyingCalls ) {
901- if ( call ?. state === 'ACTIVE' && ! call . halfCloseSent ) {
893+ if ( call ?. state === 'ACTIVE' ) {
902894 // Send halfClose immediately if all messages have been sent to this call
903895 // We check highestSentMessageIndex >= halfCloseIndex - 1 because:
904- // - If halfCloseIndex is 0, there are no messages, so send immediately
905896 // - If halfCloseIndex is N, the last message is at index N-1
906897 // - If highestSentMessageIndex >= N-1, all messages have been sent
907- if ( halfCloseIndex === 0 || call . highestSentMessageIndex >= halfCloseIndex - 1 ) {
898+ if ( call . highestSentMessageIndex >= halfCloseIndex - 1 ) {
908899 this . trace (
909900 'Sending halfClose immediately to child [' +
910901 call . call . getCallNumber ( ) +
911902 '] - all messages already sent'
912903 ) ;
913- call . halfCloseSent = true ;
904+ call . nextMessageToSend += 1 ;
914905 call . call . halfClose ( ) ;
915906 }
916907 // Otherwise, halfClose will be sent by sendNextChildMessage when messages complete
0 commit comments