1 // Copyright 2016, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 package gax 31 32 import ( 33 "context" 34 "strings" 35 "time" 36 37 "github.com/googleapis/gax-go/v2/apierror" 38 ) 39 40 // APICall is a user defined call stub. 41 type APICall func(context.Context, CallSettings) error 42 43 // Invoke calls the given APICall, performing retries as specified by opts, if 44 // any. 45 func Invoke(ctx context.Context, call APICall, opts ...CallOption) error { 46 var settings CallSettings 47 for _, opt := range opts { 48 opt.Resolve(&settings) 49 } 50 return invoke(ctx, call, settings, Sleep) 51 } 52 53 // Sleep is similar to time.Sleep, but it can be interrupted by ctx.Done() closing. 54 // If interrupted, Sleep returns ctx.Err(). 55 func Sleep(ctx context.Context, d time.Duration) error { 56 t := time.NewTimer(d) 57 select { 58 case <-ctx.Done(): 59 t.Stop() 60 return ctx.Err() 61 case <-t.C: 62 return nil 63 } 64 } 65 66 type sleeper func(ctx context.Context, d time.Duration) error 67 68 // invoke implements Invoke, taking an additional sleeper argument for testing. 69 func invoke(ctx context.Context, call APICall, settings CallSettings, sp sleeper) error { 70 var retryer Retryer 71 72 // Only use the value provided via WithTimeout if the context doesn't 73 // already have a deadline. This is important for backwards compatibility if 74 // the user already set a deadline on the context given to Invoke. 75 if _, ok := ctx.Deadline(); !ok && settings.timeout != 0 { 76 c, cc := context.WithTimeout(ctx, settings.timeout) 77 defer cc() 78 ctx = c 79 } 80 81 for { 82 err := call(ctx, settings) 83 if err == nil { 84 return nil 85 } 86 // Never retry permanent certificate errors. (e.x. if ca-certificates 87 // are not installed). We should only make very few, targeted 88 // exceptions: many (other) status=Unavailable should be retried, such 89 // as if there's a network hiccup, or the internet goes out for a 90 // minute. This is also why here we are doing string parsing instead of 91 // simply making Unavailable a non-retried code elsewhere. 92 if strings.Contains(err.Error(), "x509: certificate signed by unknown authority") { 93 return err 94 } 95 if apierr, ok := apierror.FromError(err); ok { 96 err = apierr 97 } 98 if settings.Retry == nil { 99 return err 100 } 101 if retryer == nil { 102 if r := settings.Retry(); r != nil { 103 retryer = r 104 } else { 105 return err 106 } 107 } 108 if d, ok := retryer.Retry(err); !ok { 109 return err 110 } else if err = sp(ctx, d); err != nil { 111 return err 112 } 113 } 114 } 115