@@ -616,12 +616,22 @@ func (t *http2Client) getCallAuthData(ctx context.Context, audience string, call
616
616
return callAuthData , nil
617
617
}
618
618
619
- // NewStreamError wraps an error and reports additional information.
619
+ // NewStreamError wraps an error and reports additional information. Typically
620
+ // NewStream errors result in transparent retry, as they mean nothing went onto
621
+ // the wire. However, there are two notable exceptions:
622
+ //
623
+ // 1. If the stream headers violate the max header list size allowed by the
624
+ // server. In this case there is no reason to retry at all, as it is
625
+ // assumed the RPC would continue to fail on subsequent attempts.
626
+ // 2. If the credentials errored when requesting their headers. In this case,
627
+ // it's possible a retry can fix the problem, but indefinitely transparently
628
+ // retrying is not appropriate as it is likely the credentials, if they can
629
+ // eventually succeed, would need I/O to do so.
620
630
type NewStreamError struct {
621
631
Err error
622
632
623
- DoNotRetry bool
624
- PerformedIO bool
633
+ DoNotRetry bool
634
+ DoNotTransparentRetry bool
625
635
}
626
636
627
637
func (e NewStreamError ) Error () string {
@@ -631,24 +641,10 @@ func (e NewStreamError) Error() string {
631
641
// NewStream creates a stream and registers it into the transport as "active"
632
642
// streams. All non-nil errors returned will be *NewStreamError.
633
643
func (t * http2Client ) NewStream (ctx context.Context , callHdr * CallHdr ) (_ * Stream , err error ) {
634
- defer func () {
635
- if err != nil {
636
- nse , ok := err .(* NewStreamError )
637
- if ! ok {
638
- nse = & NewStreamError {Err : err }
639
- }
640
- if len (t .perRPCCreds ) > 0 || callHdr .Creds != nil {
641
- // We may have performed I/O in the per-RPC creds callback, so do not
642
- // allow transparent retry.
643
- nse .PerformedIO = true
644
- }
645
- err = nse
646
- }
647
- }()
648
644
ctx = peer .NewContext (ctx , t .getPeer ())
649
645
headerFields , err := t .createHeaderFields (ctx , callHdr )
650
646
if err != nil {
651
- return nil , err
647
+ return nil , & NewStreamError { Err : err , DoNotTransparentRetry : true }
652
648
}
653
649
s := t .newStream (ctx , callHdr )
654
650
cleanup := func (err error ) {
@@ -748,7 +744,7 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea
748
744
return true
749
745
}, hdr )
750
746
if err != nil {
751
- return nil , err
747
+ return nil , & NewStreamError { Err : err }
752
748
}
753
749
if success {
754
750
break
@@ -759,12 +755,12 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea
759
755
firstTry = false
760
756
select {
761
757
case <- ch :
762
- case <- s . ctx .Done ():
763
- return nil , ContextErr (s . ctx .Err ())
758
+ case <- ctx .Done ():
759
+ return nil , & NewStreamError { Err : ContextErr (ctx .Err ())}
764
760
case <- t .goAway :
765
- return nil , errStreamDrain
761
+ return nil , & NewStreamError { Err : errStreamDrain }
766
762
case <- t .ctx .Done ():
767
- return nil , ErrConnClosing
763
+ return nil , & NewStreamError { Err : ErrConnClosing }
768
764
}
769
765
}
770
766
if t .statsHandler != nil {
0 commit comments