Skip to content

Instantly share code, notes, and snippets.

@krisnova
Last active July 18, 2018 18:17
Show Gist options
  • Save krisnova/13a04188d0cb5ac8ae23f2797ceb9d53 to your computer and use it in GitHub Desktop.
Save krisnova/13a04188d0cb5ac8ae23f2797ceb9d53 to your computer and use it in GitHub Desktop.

Part of the value of having an ambiguous retry package will be to be able to define ad-hoc logic.. and call it using the same method each time.

So let's look at the two things we will need in order to perform a retry.

  1. The retryer library code
  2. The retryable implementation

Imagine a Retryable inteface such as the following. The interface defines Try() method that can optionally return an error.

type Retryable interface {
  Try() error
}

Now immagine a go package that has library code to run a Retryer such as

type Retryer struct {
  retries int
  sleepSeconds int
  retryable Retryable
}

with a function that could be used to create a new Retrier

func NewRetrier(retries, sleepSeconds int, retryable Retryable) *Retrier {
  return &Retrier{
      retries: retries,
      sleepSeconds: sleepSeconds,
      retryable: retryable,
  }
}

and some simple logic to try to run a function

func (r *Retryer) RunRetry() error {
  for i := 0; i < r.retries; i++ {
    err := r.retryable.Try()
    if err != nil {
      logger.Info("Retryable error: %v", err)
      time.Sleep(time.Duration(r.sleepSeconds) * time.Second)
      continue
    }
    return nil
  }
  return fmt.Errorf("Unable to succeed at retry after %d attempts at %d seconds", r.retries, r.sleepSeconds)
}

This gives the user calling the retry code a flexible approach to running the retry.

Example implementation

Imagine a method on a struct that tried to send an HTTP request

type Request struct {
    // Information about the HTTP request
}

func (r *Request) Try(){
    // Use members from *Request to send HTTP request
    // Error if the request failed
}

We could then cleverly craft a Retry to use it in the following way:

func main() {
     request := &Request{
         // Set data for the request
     }
    r := NewRetrier(10, 1, request)
    err := r.RunRetry()
    if err != nil {
        // retry failed
    }
    // retry success
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment