-
Notifications
You must be signed in to change notification settings - Fork 12
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
Refactor TrueTime class to improve synchronization logic #51
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have been thinking there was a problem with this TrueTime implementation, but I was not able to set up a test to prove it, glad others found it :-)
For the solution, I don't understand how this can work. I think the problem is that we use (high resolution) timers, and not Date.now().
The problem being that the high resolution timer might be paused when the computer is in sleep, so the calculation: initialServerTime
+ (currentClientTime
- initialClientTime
) = will give a (server adjusted) time that is in the past if the clock was paused.
This PR updates initialServerTime
without changing initialClientTime
?
I think switching to Date.now()
will be simpler to get correct, even if the resolution might be a bit lower.
Clocks and timers are a bit of a deep-dive, but this has some good explanations and links: w3c/hr-time#115
It links several Chromium bugs I think are relevant:
https://issues.chromium.org/issues/41450546
https://issues.chromium.org/issues/40765101
https://issues.chromium.org/issues/40296804
Then we should be fine if we also sync clientStartTime along with the |
I think the problem is we can't detect if the performance time clock has been paused or not? (and so the duration between |
Guess we could store and compare a drift value of performance.now vs date.now to detect a pause? 🤔 |
…dd tests for server sync, client clock drift and performance drift.
/** | ||
* Use this method to synchronize time with the server. | ||
* | ||
* @param url - server url | ||
*/ | ||
async synchronize() { | ||
if (this.#synced) { | ||
// Synchronize at max once every 1 000 000 miliseconds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this should be allowed to run more than once, I can't see how it can work if not also setting clientStartTime
?
if ( | ||
(this.#synced && Math.abs(this.#synced - Date.now()) < 1_000_000) || | ||
(this.#synced && | ||
Math.abs(this.#initialDrift - this.currentDrift()) < 1_000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This "feels" like it is getting complicated, are we sure there are any benefits to not just replacing performance.now()
with Date.now()
and keeping this module simple?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we'd have to re-implement performance.mark() with Date.now too... :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it is a bit unfortunate that that is mixed in here, makes this more complex than it should be :-(
Might need to think a bit how we can avoid that..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I solved it in the other PR by setting startTime
in each performance.mark()
call, we can also consider making a trueTime.mark()
that abstracts that maybe?
Suggestion (possibly dumb): race calls to different time providing servers like google, apple and idk? for the initial timestamp. Might yield some minor improvement based on location and or downtimes? Iterative in a next pr ofc |
I added an alternative solution: #66 I think that is simpler and less fragile? |
Looks more sane, but with that we still have 2 issues that this PR doesn't:
|
Yes can try to bring that over from this PR! (not sure how commonly it happens, but should not hurt to be on the safe side :-) )
I don't think I understand the expectation here? ( |
Ported: 899eb92 (could now also remove the |
Ah okey, if it's not guaranteed to be frozen then never mind. Guess those cases could be detected by back-end and adjusted/filtered properly anyway. I'll close this and we'll put our bets on your PR :) |
Long over-night or over-weekend sessions could get wrong timestamps.
This pull request includes changes to the
TrueTime
class in thepackages/true-time/src/index.ts
file. The changes are focused on modifying the#synced
private member and its usage in thesynchronize
method to ensure the synchronization process doesn't occur more frequently than once every 1,000,000 milliseconds.packages/true-time/src/index.ts
: The#synced
private member was modified from a boolean to a number or undefined. This change allows the storage of the timestamp of the last successful synchronization.packages/true-time/src/index.ts
: In thesynchronize
method, a check was added to ensure that synchronization doesn't occur if the last successful synchronization was less than 1,000,000 milliseconds ago.packages/true-time/src/index.ts
: The#synced
private member is now set to the current timestamp (Date.now()
) after a successful synchronization.