Skip to content
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

Improvements to time syncing #2493

Merged
Show file tree
Hide file tree
Changes from all 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
13 changes: 8 additions & 5 deletions frontend/controller/actions/group-kv.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ export default (sbp('sbp/selectors/register', {
console.info('group key-value store data loaded!')
},
'gi.actions/group/kv/fetchLastLoggedIn': async ({ contractID }: { contractID: string }) => {
return (await sbp('chelonia/kv/get', contractID, KV_KEYS.LAST_LOGGED_IN).catch((e) => {
console.error('[gi.actions/group/kv/fetchLastLoggedIn] Error', e)
}))?.data || Object.create(null)
return (await sbp('chelonia/kv/get', contractID, KV_KEYS.LAST_LOGGED_IN))?.data || Object.create(null)
},
'gi.actions/group/kv/loadLastLoggedIn': ({ contractID }: { contractID: string }) => {
return sbp('okTurtles.eventQueue/queueEvent', KV_QUEUE, async () => {
const data = await sbp('gi.actions/group/kv/fetchLastLoggedIn', { contractID })
sbp('okTurtles.events/emit', NEW_LAST_LOGGED_IN, [contractID, data])
}).catch(e => {
console.error('[gi.actions/group/kv/loadLastLoggedIn] Error loading last logged in', e)
})
},
'gi.actions/group/kv/updateLastLoggedIn': ({ contractID, throttle }: { contractID: string, throttle: boolean }) => {
Expand All @@ -48,9 +48,12 @@ export default (sbp('sbp/selectors/register', {

if (throttle) {
const state = sbp('state/vuex/state')
const lastLoggedIn = new Date(state.lastLoggedIn?.[contractID]?.[identityContractID]).getTime()
const lastLoggedInRawValue: ?string = state.lastLoggedIn?.[contractID]?.[identityContractID]
if (lastLoggedInRawValue) {
const lastLoggedIn = new Date(lastLoggedInRawValue).getTime()

if ((Date.now() - lastLoggedIn) < LAST_LOGGED_IN_THROTTLE_WINDOW) return
if ((Date.now() - lastLoggedIn) < LAST_LOGGED_IN_THROTTLE_WINDOW) return
}
}

const now = new Date().toISOString()
Expand Down
17 changes: 13 additions & 4 deletions shared/domains/chelonia/time-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ let watchdog

const syncServerTime = async function () {
// Get our current monotonic time
const newMonotonicBase = performance.now()
const startTime = performance.now()
// Now, ask the server for the time
const time = await fetch(`${this.config.connectionURL}/time`, { signal: this.abortController.signal })
const requestTimeElapsed = performance.now()
if (requestTimeElapsed - newMonotonicBase > 1000) {
if (requestTimeElapsed - startTime > 8000) {
throw new Error('Error fetching server time: request took too long')
}
// If the request didn't succeed, report it
Expand All @@ -34,12 +34,21 @@ const syncServerTime = async function () {
// Adjust `wallBase` based on the elapsed request time. We can't know
// how long it took for the server to respond, but we can estimate that it's
// about half the time from the moment we made the request.
wallBase = serverTime + (requestTimeElapsed - newMonotonicBase) / 2
const newMonotonicBase = performance.now()
wallBase =
serverTime +
(requestTimeElapsed - startTime) / 2 +
// Also take into account the time elapsed between `requestTimeElapsed`
// and this line (which should be very little)
(newMonotonicBase - requestTimeElapsed)
corrideat marked this conversation as resolved.
Show resolved Hide resolved
monotonicBase = newMonotonicBase
}

export default (sbp('sbp/selectors/register', {
'chelonia/private/startClockSync': function () {
if (resyncTimeout !== undefined) {
throw new Error('chelonia/private/startClockSync has already been called')
}
// Default re-sync every 5 minutes
const resync = (delay: number = 300000) => {
// If there's another time sync process in progress, don't do anything
Expand Down Expand Up @@ -104,7 +113,7 @@ export default (sbp('sbp/selectors/register', {
// measured locally (using a monotonic clock), which is used as an offset, and
// a previously retrieved server time. The time value is returned as a UNIX
// timestamp (seconds since 1 Jan 1970 00:00:00 UTC)
'chelonia/time': function () {
'chelonia/time': function (): number {
const monotonicNow = performance.now()
const wallNow = wallBase - monotonicBase + monotonicNow
return (wallNow / 1e3 | 0)
Expand Down