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

Conversation

mikelehen
Copy link
Contributor

No description provided.

@mikelehen
Copy link
Contributor Author

On the fence on whether this warrants a changelog entry. Backoff is mostly an implementation detail and it'd be hard to describe the user-facing change in behavior very precisely.

Copy link
Contributor

@wilhuff wilhuff left a comment

Choose a reason for hiding this comment

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

I agree that no changelog entry is required (though if nothing else shows up we'll need to add an "internal improvements" entry).

@@ -31,6 +31,7 @@ const LOG_TAG = 'ExponentialBackoff';
export class ExponentialBackoff {
private currentBaseMs: number;
private timerPromise: CancelablePromise<void> | null = null;
private lastAttempt: Date = new Date(0);
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the "current time" is not a portably expressed, maybe make this lastAttemptTime stored as a number?

That way we don't have two different ways of reading the current time in the code (currently new Date().getTime() vs new Date()).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed to lastAttemptTime and switched to epoch milliseconds.

);

// Some time may have already elapsed so account for that.
const delaySoFarMs = new Date().getTime() - this.lastAttempt.getTime();
Copy link
Contributor

Choose a reason for hiding this comment

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

This makes me nervous: new Date().getTime() is not guaranteed to be a monotonic time source. At least it's guaranteed to be in UTC so there's no timezone bug here, but large time adjustments backwards could result in negative values for delaySoFarMs. We should probably ensure this is no smaller than zero so the next line doesn't end up with arbitrarily large delays.

If this class accepted a ticker constructor parameter that returned a new timestamp in ms on each call this logic could be tested.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair point. Reworked to ensure it's >= 0. I don't love the way this code looks (doing Math.max(0, ...) twice in a row for different reasons) but I tried rewriting it a couple different ways and it didn't get much better, so I'm just relying on comments.

I almost considered doing the ticker thing and adding tests, but I think we'd need a mockable random number generator too and if I do that I won't get this ported to the other 2 clients before going OOO. So I just tested it manually again. 😛

If you think it's time to bite the bullet and automate tests, I can though.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm OK this as is.

Copy link
Contributor

@wilhuff wilhuff left a comment

Choose a reason for hiding this comment

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

LGTM with final nits

);

// Some time may have already elapsed so account for that.
const delaySoFarMs = new Date().getTime() - this.lastAttempt.getTime();
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm OK this as is.


// 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.

@wilhuff wilhuff assigned mikelehen and unassigned wilhuff Aug 17, 2018
Copy link
Contributor Author

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

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

Comments addressed. Thanks!


// 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 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 Author

Choose a reason for hiding this comment

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

Done.

@mikelehen mikelehen merged commit 95f3d18 into master Aug 17, 2018
@mikelehen mikelehen deleted the mikelehen/backoff-improvement branch August 17, 2018 16:24
mikelehen pushed a commit to firebase/firebase-ios-sdk that referenced this pull request Aug 17, 2018
mikelehen added a commit to firebase/firebase-ios-sdk that referenced this pull request Aug 18, 2018
* Make backoff account for already-elapsed time.

[Port of firebase/firebase-js-sdk#1132]
mikelehen pushed a commit to firebase/firebase-ios-sdk that referenced this pull request Sep 6, 2018
mikelehen added a commit to firebase/firebase-ios-sdk that referenced this pull request Sep 7, 2018
* Make C++ exponential backoff account for already-elapsed time.

[Port of firebase/firebase-js-sdk#1132]
@firebase firebase locked and limited conversation to collaborators Oct 17, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants