Skip to content

Instantly share code, notes, and snippets.

@franklinharvey
Last active May 3, 2020 00:44
Show Gist options
  • Save franklinharvey/a8a09fa7dfb1f53edda2cc764cb8b865 to your computer and use it in GitHub Desktop.
Save franklinharvey/a8a09fa7dfb1f53edda2cc764cb8b865 to your computer and use it in GitHub Desktop.
Full Jitter Exponential Backoff Algorithm
const BASE_TIMEOUT = 5 // in milliseconds, you can change this
const getTimeout = (attempt: number): number => {
const backoff = BASE_TIMEOUT * Math.pow(2, attempt) // exp. increases the timeout per attempt
const backoff_or_cap = Math.min(1000, backoff) // cap the timeout at 1 sec.
const ret = sample([0, backoff_or_cap]) // randomly choose between 0 and the backoff, this is the "jitter" part
return ret
}
// randomly choose from an array, a replacement of lodash's sample method
const sample = (arr: number[]) => {
const len = arr == null ? 0 : arr.length
return len ? arr[Math.floor(Math.random() * len)] : undefined
}
// here's an example of how it's used with DynamoDB, but this principle applies for any case where you need to batch operations but some number of those operations may conflict and need to be retried
class ExampleDynamoDBClass {
db: DynamoDB
MAX_ATTEMPTS = 3
public onDBWrite = (input: DynamoDB.PutItemInput, attempt: number = 1): Promise<void> => {
return new Promise((resolve, reject) => {
this.db.putItem(input, (err, _) => {
if (err) {
if (attempt <= this.MAX_ATTEMPTS) {
const timeout = getTimeout(attempt)
console.log(`[putItem] write failed(${err}), retrying(attempt ${attempt}, backoff: ${timeout}ms)`)
setTimeout(() => {
resolve(this.onDBWrite(input, attempt + 1))
}, timeout)
} else {
reject(`[putItem] ${err}: ${JSON.stringify(input)}`)
}
}
else resolve()
})
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment