shouldRetry returns nil if the RPC should be retried; otherwise it returns the error that should be returned by the operation. If the RPC should be retried, the bool indicates whether it is being retried transparently.
(err error)
| 684 | // the error that should be returned by the operation. If the RPC should be |
| 685 | // retried, the bool indicates whether it is being retried transparently. |
| 686 | func (a *csAttempt) shouldRetry(err error) (bool, error) { |
| 687 | cs := a.cs |
| 688 | |
| 689 | if cs.finished || cs.committed || a.drop { |
| 690 | // RPC is finished or committed or was dropped by the picker; cannot retry. |
| 691 | return false, err |
| 692 | } |
| 693 | if a.transportStream == nil && a.allowTransparentRetry { |
| 694 | return true, nil |
| 695 | } |
| 696 | // Wait for the trailers. |
| 697 | unprocessed := false |
| 698 | if a.transportStream != nil { |
| 699 | <-a.transportStream.Done() |
| 700 | unprocessed = a.transportStream.Unprocessed() |
| 701 | } |
| 702 | if cs.firstAttempt && unprocessed { |
| 703 | // First attempt, stream unprocessed: transparently retry. |
| 704 | return true, nil |
| 705 | } |
| 706 | if cs.cc.dopts.disableRetry { |
| 707 | return false, err |
| 708 | } |
| 709 | |
| 710 | pushback := 0 |
| 711 | hasPushback := false |
| 712 | if a.transportStream != nil { |
| 713 | if !a.transportStream.TrailersOnly() { |
| 714 | return false, err |
| 715 | } |
| 716 | |
| 717 | // TODO(retry): Move down if the spec changes to not check server pushback |
| 718 | // before considering this a failure for throttling. |
| 719 | sps := a.transportStream.Trailer()["grpc-retry-pushback-ms"] |
| 720 | if len(sps) == 1 { |
| 721 | var e error |
| 722 | if pushback, e = strconv.Atoi(sps[0]); e != nil || pushback < 0 { |
| 723 | channelz.Infof(logger, cs.cc.channelz, "Server retry pushback specified to abort (%q).", sps[0]) |
| 724 | cs.retryThrottler.throttle() // This counts as a failure for throttling. |
| 725 | return false, err |
| 726 | } |
| 727 | hasPushback = true |
| 728 | } else if len(sps) > 1 { |
| 729 | channelz.Warningf(logger, cs.cc.channelz, "Server retry pushback specified multiple values (%q); not retrying.", sps) |
| 730 | cs.retryThrottler.throttle() // This counts as a failure for throttling. |
| 731 | return false, err |
| 732 | } |
| 733 | } |
| 734 | |
| 735 | var code codes.Code |
| 736 | if a.transportStream != nil { |
| 737 | code = a.transportStream.Status().Code() |
| 738 | } else { |
| 739 | code = status.Code(err) |
| 740 | } |
| 741 | |
| 742 | rp := cs.methodConfig.RetryPolicy |
| 743 | if rp == nil || !rp.RetryableStatusCodes[code] { |
no test coverage detected