// 2017 Rackspace, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. // Package tools serves as helper or utility functions for other applications within the Migrations App. package tools import ( "math/rand" "time" ) // StopRetry type is a specific type to test // against so that we can purposely break the // retry loop external to this package. type StopRetry struct { error } func init() { rand.Seed(time.Now().UnixNano()) } // Retry function will take a func Retry(attempts int, sleep time.Duration, f func() error) error { // If there was an error in the calling function, check to see if the // error type is of type StopRety, if so, return the error back to the client. // However, if we are still in the attempt loop, recursively call the Retry // function again. if err := f(); err != nil { if s, ok := err.(StopRetry); ok { // Return the original error for later checking return s.error } if attempts--; attempts > 0 { // Adjust sleep timer for a random interval to prevent too many // request hammering the call at once. //nolint:gosec sleep = sleep + time.Duration(rand.Int63n(int64(sleep)))/2 // Pause and wait for the specified interval time.Sleep(sleep) // Recursively call the Retry function again. return Retry(attempts, 2*sleep, f) } // If we are outside of the attempt count, go ahead and return the // error. return err } // Represents a successful call. return nil }