Skip to content

Make backoff account for already-elapsed time. #1132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 17, 2018
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions packages/firestore/src/remote/backoff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const LOG_TAG = 'ExponentialBackoff';
export class ExponentialBackoff {
private currentBaseMs: number;
private timerPromise: CancelablePromise<void> | null = null;
/** The last backoff attempt, as epoch milliseconds. */
private lastAttemptTime = Date.now();

constructor(
/**
Expand Down Expand Up @@ -92,18 +94,39 @@ export class ExponentialBackoff {

// First schedule using the current base (which may be 0 and should be
// honored as such).
const delayWithJitterMs = this.currentBaseMs + this.jitterDelayMs();
const desiredDelayWithJitterMs = Math.floor(
this.currentBaseMs + this.jitterDelayMs()
);

// Some time may have already elapsed so account for that.

// Math.max(0, ...) to guard against lastAttemptTime being in the future due
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: rather than repeating the function you're calling, just describe what's happening, i.e.

// Guard against lastAttemptTime being in the future due to a clock change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM, done.

// to a clock change.
const delaySoFarMs = Math.max(0, Date.now() - this.lastAttemptTime);

// Math.max(0, ...) because the desired backoff may already be elapsed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think the "Some time may have already elapsed" somewhat duplicates this line. Consider axing it.

(also drop "Max.max ... because")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

const remainingDelayMs = Math.max(
0,
desiredDelayWithJitterMs - delaySoFarMs
);

if (this.currentBaseMs > 0) {
log.debug(
LOG_TAG,
`Backing off for ${delayWithJitterMs} ms ` +
`(base delay: ${this.currentBaseMs} ms)`
`Backing off for ${remainingDelayMs} ms ` +
`(base delay: ${this.currentBaseMs} ms, ` +
`delay with jitter: ${desiredDelayWithJitterMs} ms, ` +
`last attempt: ${delaySoFarMs} ms ago)`
);
}

this.timerPromise = this.queue.enqueueAfterDelay(
this.timerId,
delayWithJitterMs,
op
remainingDelayMs,
() => {
this.lastAttemptTime = Date.now();
return op();
}
);

// Apply backoff factor to determine next delay and ensure it is within
Expand Down