mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-01-14 17:07:15 -05:00
64 lines
1.2 KiB
Go
64 lines
1.2 KiB
Go
package retry
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
"k8s.io/utils/clock"
|
|
)
|
|
|
|
type IntervalRetryer struct {
|
|
interval time.Duration
|
|
doer Doer
|
|
clock clock.WithTicker
|
|
}
|
|
|
|
func NewIntervalRetryer(doer Doer, interval time.Duration) *IntervalRetryer {
|
|
return &IntervalRetryer{
|
|
interval: interval,
|
|
doer: doer,
|
|
clock: clock.RealClock{},
|
|
}
|
|
}
|
|
|
|
func (r *IntervalRetryer) Do(ctx context.Context) error {
|
|
ticker := r.clock.NewTicker(r.interval)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
err := r.doer.Do(ctx)
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
if !r.serviceIsUnavailable(err) {
|
|
return err
|
|
}
|
|
|
|
select {
|
|
case <-ctx.Done(): // TODO(katexochen): is this necessary?
|
|
return ctx.Err()
|
|
case <-ticker.C():
|
|
}
|
|
}
|
|
}
|
|
|
|
func (r *IntervalRetryer) serviceIsUnavailable(err error) bool {
|
|
statusErr, ok := status.FromError(err)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if statusErr.Code() != codes.Unavailable {
|
|
return false
|
|
}
|
|
// ideally we would check the error type directly, but grpc only provides a string
|
|
return strings.HasPrefix(statusErr.Message(), `connection error: desc = "transport: authentication handshake failed`)
|
|
}
|
|
|
|
type Doer interface {
|
|
Do(ctx context.Context) error
|
|
}
|