Skip to content

Unify backoff retry mechanisms #6985

@jsoref

Description

@jsoref

Backoff

One such library already in use in our codebase seems to be used in Codespaces code:

expBackoff := backoff.NewExponentialBackOff()
expBackoff.Multiplier = 1.1
expBackoff.MaxInterval = 10 * time.Second
expBackoff.MaxElapsedTime = 5 * time.Minute

Throughout the gh codebase, we definitely have ad-hoc implementations for this in too many places, and the implementations are not even that good. Example:

pushTries++
// first wait 2 seconds after forking, then 4s, then 6s
waitSeconds := 2 * pushTries
fmt.Fprintf(opts.IO.ErrOut, "waiting %s before retrying...\n", text.Pluralize(waitSeconds, "second"))
time.Sleep(time.Duration(waitSeconds) * time.Second)

Originally posted by @mislav in #6962 (comment)

Sleep

Testable Go code should never be allowed to sleep the same period of time in tests as it does during normal runtime. Even a relatively short duration like sleeping 100ms would make tests really slow. Finding a way to inject a shorter (fake) Duration in tests would be crucial.

Also, the Sleep statement would not return early if a Context has been cancelled, therefore if a Context is involved, it would be better to use a Timer and use a select statement to react to either a Timer completing or a Context being cancelled, whichever comes first. Example: https://github.com/cli/oauth/blob/adf5f733ffd14993aad9f3ff02c757a737f7c63b/device/poller.go#L30-L37

Originally posted by @mislav in #6962 (comment)

Proposal

  • Replace all ad-hoc mechanisms with the backoff mechanism used by codespaces.
  • Replace most instances of time.Sleep() with a polling thing that handles cancelation and makes it easier for testing to tune durations.

Metadata

Metadata

Assignees

Labels

enhancementa request to improve CLItech-debtA chore that addresses technical debt

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions