-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
nodeadm: block until daemon status changes are reflected (#1965)
- Loading branch information
Showing
5 changed files
with
110 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,21 @@ | ||
package daemon | ||
|
||
import "github.com/awslabs/amazon-eks-ami/nodeadm/internal/api" | ||
import ( | ||
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/api" | ||
) | ||
|
||
type Daemon interface { | ||
// Configure configures the daemon. | ||
Configure(*api.NodeConfig) error | ||
|
||
// EnsureRunning ensures that the daemon is running. | ||
// If the daemon is not running, it will be started. | ||
// If the daemon is already running, and has been re-configured, it will be restarted. | ||
// EnsureRunning ensures that the daemon is running by either | ||
// starting/restarting the daemon, then blocking until the status of the | ||
// daemon reflects that it is running. | ||
// * If the daemon is not running, it will be started. | ||
// * If the daemon is already running, and has been re-configured, it will be restarted. | ||
EnsureRunning() error | ||
|
||
// PostLaunch runs any additional step that needs to occur after the service | ||
// daemon as been started | ||
PostLaunch(*api.NodeConfig) error | ||
|
||
// Name returns the name of the daemon. | ||
Name() string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,73 @@ | ||
package util | ||
|
||
import "time" | ||
|
||
func RetryExponentialBackoff(attempts int, initial time.Duration, f func() error) error { | ||
var err error | ||
wait := initial | ||
for i := 0; i < attempts; i++ { | ||
if err = f(); err == nil { | ||
return nil | ||
import ( | ||
"context" | ||
"time" | ||
) | ||
|
||
type Retrier struct { | ||
ConditionFn func(*Retrier) bool | ||
BackoffFn func(*Retrier) time.Duration | ||
|
||
LastErr error | ||
LastWait time.Duration | ||
LastIter int | ||
} | ||
|
||
func (r *Retrier) Retry(ctx context.Context, fn func() error) error { | ||
for r.LastIter = 0; r.ConditionFn(r); r.LastIter++ { | ||
if r.LastErr = fn(); r.LastErr == nil { | ||
return r.LastErr | ||
} | ||
select { | ||
case <-ctx.Done(): | ||
return ctx.Err() | ||
default: | ||
time.Sleep(r.LastWait) | ||
r.LastWait = r.BackoffFn(r) | ||
} | ||
time.Sleep(wait) | ||
wait *= 2 | ||
} | ||
return err | ||
return r.LastErr | ||
} | ||
|
||
type fnOpt func(*Retrier) | ||
|
||
func NewRetrier(fnOpts ...fnOpt) *Retrier { | ||
retrier := Retrier{ | ||
LastErr: nil, | ||
LastIter: 0, | ||
LastWait: time.Second, | ||
} | ||
for _, fn := range append([]fnOpt{ | ||
WithRetryCount(5), | ||
WithBackoffExponential(), | ||
}, fnOpts...) { | ||
fn(&retrier) | ||
} | ||
return &retrier | ||
} | ||
|
||
func WithRetryCount(maxAttempts int) fnOpt { | ||
return func(r *Retrier) { | ||
r.ConditionFn = func(r *Retrier) bool { return r.LastIter < maxAttempts } | ||
} | ||
} | ||
|
||
func WithRetryAlways() fnOpt { | ||
return func(r *Retrier) { | ||
r.ConditionFn = func(r *Retrier) bool { return true } | ||
} | ||
} | ||
|
||
func WithBackoffFixed(interval time.Duration) fnOpt { | ||
return func(r *Retrier) { | ||
r.LastWait = interval | ||
r.BackoffFn = func(r *Retrier) time.Duration { return interval } | ||
} | ||
} | ||
|
||
func WithBackoffExponential() fnOpt { | ||
return func(r *Retrier) { | ||
r.BackoffFn = func(r *Retrier) time.Duration { return r.LastWait * 2 } | ||
} | ||
} |