From 4385e0b9c9a641ad239ac17cef4a269190694d19 Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Sun, 7 Sep 2025 19:22:36 +0200 Subject: [PATCH] refactor: ensure clocks timer and clock are in sync (#1772) * refactor: ensure clocks timer and clock are in sync --------- Co-authored-by: arc-alex --- .../runtime-service/runtime.service.ts | 37 ++++++++++++------- .../services/runtime-service/runtime.utils.ts | 13 +++++-- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/apps/server/src/services/runtime-service/runtime.service.ts b/apps/server/src/services/runtime-service/runtime.service.ts index a5b7b2bb7..10dca10b9 100644 --- a/apps/server/src/services/runtime-service/runtime.service.ts +++ b/apps/server/src/services/runtime-service/runtime.service.ts @@ -636,6 +636,8 @@ const eventTimer = new EventTimer({ }); export const runtimeService = new RuntimeService(eventTimer); +type EntryUpdateKeys = keyof Pick; + /** * Decorator manages side effects from updating the runtime * This should only be applied to functions that are exposed for consumption @@ -672,21 +674,30 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert // combine all big changes const hasImmediateChanges = entryChanged || justStarted || hasChangedPlayback || offsetModeChanged; - // clock has changed by a second or more - const updateClock = getShouldClockUpdate(RuntimeService.previousState.clock, state.clock); - if (updateClock) { - batch.add('clock', state.clock); - RuntimeService.previousState.clock = state.clock; - } - - // if any values have changed, values that have the possibility to tick are updated when the seconds roll over + /** + * if any values have changed. + * values that have the possibility to tick are updated when the seconds roll over + */ const updateTimer = getShouldTimerUpdate(RuntimeService.previousState?.timer, state.timer); if (updateTimer) { batch.add('timer', state.timer); RuntimeService.previousState.timer = { ...state.timer }; } - // if any values have changed, values that have the possibility to tick are modulated by `hasClockUpdate` + /** + * clock has changed by a second or more. + * or the timer updated so we ensure that the timer and clock ticks are in sync + */ + const updateClock = updateTimer || getShouldClockUpdate(RuntimeService.previousState.clock, state.clock); + if (updateClock) { + batch.add('clock', state.clock); + RuntimeService.previousState.clock = state.clock; + } + + /** + * if any values have changed. + * values that have the possibility to tick are modulated by `updateClock || hasImmediateChanges` + */ const updateRuntime = getShouldOffsetUpdate( RuntimeService.previousState?.offset, state.offset, @@ -697,16 +708,16 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert RuntimeService.previousState.offset = structuredClone(state.offset); } - // if any values have changed + /** + * if any values have changed. + */ const updateRundownData = !deepEqual(RuntimeService.previousState.rundown, state.rundown); if (updateRundownData) { batch.add('rundown', state.rundown); RuntimeService.previousState.rundown = structuredClone(state.rundown); } - function updateMaybeEntryIfChanged< - K extends keyof Pick, - >(key: K) { + function updateMaybeEntryIfChanged(key: K) { const previousEntry = RuntimeService.previousState[key]; const currentEntry = state[key]; diff --git a/apps/server/src/services/runtime-service/runtime.utils.ts b/apps/server/src/services/runtime-service/runtime.utils.ts index 19280d367..2a1c62269 100644 --- a/apps/server/src/services/runtime-service/runtime.utils.ts +++ b/apps/server/src/services/runtime-service/runtime.utils.ts @@ -24,7 +24,6 @@ export function isNewSecond( /** * Checks whether we should update the clock value * - we have rolled into a new seconds unit - * this is different from the timer update as it looks at the clock as counting up */ export function getShouldClockUpdate(previousUpdate: number, now: number): boolean { const newSeconds = millisToSeconds(now, TimerType.CountUp) !== millisToSeconds(previousUpdate, TimerType.CountUp); @@ -32,8 +31,10 @@ export function getShouldClockUpdate(previousUpdate: number, now: number): boole } /** - * Checks whether we should update the timer value - * - we have rolled into a new seconds unit + * Checks whether we should update the timer values + * - `current` and `secondaryTimer` trigger on seconds roll over + * - the rest trigger on any change + * - `elapsed` and `expectedFinish` is not checked */ export function getShouldTimerUpdate(previousValue: TimerState | undefined, currentValue: TimerState): boolean { if (previousValue === undefined) return true; @@ -53,6 +54,11 @@ export function getShouldTimerUpdate(previousValue: TimerState | undefined, curr ); } +/** + * Checks whether we should update the offset values + * - `mode` triggers update + * - `absolute`, `relative`, `expected**End` are ticked with `didDependencyUpdate` + */ export function getShouldOffsetUpdate( previousValue: Offset | undefined, currentValue: Offset, @@ -60,7 +66,6 @@ export function getShouldOffsetUpdate( ): boolean { if (previousValue === undefined) return true; if (previousValue.mode !== currentValue.mode) return true; - // absolute, relative, expected*End are ticked with `didDependencyUpdate` return didDependencyUpdate && !deepEqual(previousValue, currentValue); }