wait.go raw

   1  package wait
   2  
   3  import (
   4  	"context"
   5  	"fmt"
   6  	"time"
   7  
   8  	"github.com/cenkalti/backoff/v5"
   9  	"github.com/go-acme/lego/v4/log"
  10  )
  11  
  12  // For polls the given function 'f', once every 'interval', up to 'timeout'.
  13  func For(msg string, timeout, interval time.Duration, f func() (bool, error)) error {
  14  	log.Infof("Wait for %s [timeout: %s, interval: %s]", msg, timeout, interval)
  15  
  16  	var lastErr error
  17  
  18  	timeUp := time.After(timeout)
  19  
  20  	for {
  21  		select {
  22  		case <-timeUp:
  23  			if lastErr == nil {
  24  				return fmt.Errorf("%s: time limit exceeded", msg)
  25  			}
  26  
  27  			return fmt.Errorf("%s: time limit exceeded: last error: %w", msg, lastErr)
  28  		default:
  29  		}
  30  
  31  		stop, err := f()
  32  		if stop {
  33  			return err
  34  		}
  35  
  36  		if err != nil {
  37  			lastErr = err
  38  		}
  39  
  40  		time.Sleep(interval)
  41  	}
  42  }
  43  
  44  // Retry retries the given operation until it succeeds or the context is canceled.
  45  // Similar to [backoff.Retry] but with a different signature.
  46  func Retry(ctx context.Context, operation func() error, opts ...backoff.RetryOption) error {
  47  	_, err := backoff.Retry(ctx, func() (any, error) {
  48  		return nil, operation()
  49  	}, opts...)
  50  
  51  	return err
  52  }
  53