refactor: improve integration updates

This commit is contained in:
Carlos Valente
2024-05-11 11:53:32 +02:00
committed by Carlos Valente
parent c57b0423af
commit 07074260a4
3 changed files with 41 additions and 47 deletions
@@ -20,7 +20,7 @@ import {
getPlayableEvents, getPlayableEvents,
} from '../rundown-service/rundownUtils.js'; } from '../rundown-service/rundownUtils.js';
import { integrationService } from '../integration-service/IntegrationService.js'; import { integrationService } from '../integration-service/IntegrationService.js';
import { getShouldClockUpdate, getShouldTimerUpdate } from './rundownService.utils.js'; import { getForceUpdate, getShouldClockUpdate, getShouldTimerUpdate } from './rundownService.utils.js';
/** /**
* Service manages runtime status of app * Service manages runtime status of app
@@ -28,7 +28,8 @@ import { getShouldClockUpdate, getShouldTimerUpdate } from './rundownService.uti
*/ */
class RuntimeService { class RuntimeService {
private eventTimer: TimerService | null = null; private eventTimer: TimerService | null = null;
private lastOnUpdate = -1; private lastIntegrationClockUpdate = -1;
private lastIntegrationTimerValue = -1;
/** last time we updated the socket */ /** last time we updated the socket */
static previousTimerUpdate: number; static previousTimerUpdate: number;
@@ -66,19 +67,25 @@ class RuntimeService {
} }
} }
// update normal cycle const hasRunningTimer = Boolean(newState.eventNow) && newState.timer.playback === Playback.Play;
if (newState.clock - this.lastOnUpdate >= timerConfig.notificationRate) { const shouldUpdateTimer =
const hasRunningTimer = Boolean(newState.eventNow) && newState.timer.playback === Playback.Play; hasRunningTimer && getShouldTimerUpdate(this.lastIntegrationTimerValue, newState.timer.current);
if (hasRunningTimer) {
process.nextTick(() => { if (shouldUpdateTimer) {
integrationService.dispatch(TimerLifeCycle.onUpdate); process.nextTick(() => {
}); integrationService.dispatch(TimerLifeCycle.onUpdate);
} });
this.lastIntegrationTimerValue = newState.timer.current;
}
const shouldUpdateClock = getShouldClockUpdate(this.lastIntegrationClockUpdate, newState.clock);
if (shouldUpdateClock) {
process.nextTick(() => { process.nextTick(() => {
integrationService.dispatch(TimerLifeCycle.onClock); integrationService.dispatch(TimerLifeCycle.onClock);
}); });
this.lastOnUpdate = newState.clock; this.lastIntegrationClockUpdate = newState.clock;
} }
if (shouldCallRoll) { if (shouldCallRoll) {
@@ -522,12 +529,9 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
// to apply custom logic for different datasets // to apply custom logic for different datasets
const shouldUpdateClock = getShouldClockUpdate(RuntimeService.previousClockUpdate, state.clock); const shouldUpdateClock = getShouldClockUpdate(RuntimeService.previousClockUpdate, state.clock);
const shouldUpdateTimer = getShouldTimerUpdate( const shouldForceTimerUpdate = getForceUpdate(RuntimeService.previousTimerUpdate, state.clock);
RuntimeService.previousTimerValue, const shouldUpdateTimer =
state.timer.current, shouldForceTimerUpdate || getShouldTimerUpdate(RuntimeService.previousTimerValue, state.timer.current);
RuntimeService.previousTimerUpdate,
state.clock,
);
// some changes need an immediate update // some changes need an immediate update
const hasNewLoaded = state.eventNow?.id !== RuntimeService.previousState?.eventNow?.id; const hasNewLoaded = state.eventNow?.id !== RuntimeService.previousState?.eventNow?.id;
@@ -35,27 +35,28 @@ describe('getShouldTimerUpdate', () => {
it('should return false when currentValue is null', () => { it('should return false when currentValue is null', () => {
const previousValue = 0; const previousValue = 0;
const currentValue = null; const currentValue = null;
const previousUpdate = 0; const result = getShouldTimerUpdate(previousValue, currentValue);
const now = 0;
const result = getShouldTimerUpdate(previousValue, currentValue, previousUpdate, now);
expect(result).toBe(false); expect(result).toBe(false);
}); });
it('should return true when timer is a second ahead', () => { it('should return true when timer is a second ahead', () => {
const previousValue = 5000; const previousValue = 6500;
const currentValue = 6500; const currentValue = 5000;
const previousUpdate = Date.now(); const result = getShouldTimerUpdate(previousValue, currentValue);
const now = Date.now();
const result = getShouldTimerUpdate(previousValue, currentValue, previousUpdate, now);
expect(result).toBe(true); expect(result).toBe(true);
}); });
it('should return false when timer is not a second ahead and force update is not required', () => { it('should return false when timer is not a second ahead', () => {
const previousValue = 5000; const previousValue = 5500;
const currentValue = 5500; const currentValue = 5200;
const previousUpdate = Date.now(); const result = getShouldTimerUpdate(previousValue, currentValue);
const now = Date.now();
const result = getShouldTimerUpdate(previousValue, currentValue, previousUpdate, now);
expect(result).toBe(false); expect(result).toBe(false);
}); });
it('timer value is ceiled', () => {
const previousValue = 5001; // 6
const currentValue = 4999; // 5
const result = getShouldTimerUpdate(previousValue, currentValue);
expect(result).toBe(true);
});
}); });
@@ -19,26 +19,15 @@ export function getShouldClockUpdate(previousUpdate: number, now: number): boole
/** /**
* Checks whether we should update the timer value * Checks whether we should update the timer value
* - timer has slid (?)
* - we have rolled into a new seconds unit * - we have rolled into a new seconds unit
*/ */
export function getShouldTimerUpdate( export function getShouldTimerUpdate(previousValue: number, currentValue: MaybeNumber): boolean {
previousValue: number,
currentValue: MaybeNumber,
previousUpdate: number,
now: number,
): boolean {
if (currentValue === null) { if (currentValue === null) {
return false; return false;
} }
// we avoid trigger ahead since it can cause duplicate triggers
const shouldForceUpdate = getForceUpdate(previousUpdate, now); // we force the timer value to be negative because we need a ceiling reduction
if (shouldForceUpdate) { const shouldUpdateTimer = millisToSeconds(-currentValue) !== millisToSeconds(-previousValue);
return true;
}
const shouldUpdateTimer = millisToSeconds(currentValue) !== millisToSeconds(previousValue + timerConfig.triggerAhead);
return shouldUpdateTimer; return shouldUpdateTimer;
} }
@@ -47,7 +36,7 @@ export function getShouldTimerUpdate(
* - if the clock has slid back * - if the clock has slid back
* - if we have escaped the update rate (clock slid forward) * - if we have escaped the update rate (clock slid forward)
*/ */
function getForceUpdate(previousUpdate: number, now: number): boolean { export function getForceUpdate(previousUpdate: number, now: number): boolean {
const isClockBehind = now < previousUpdate; const isClockBehind = now < previousUpdate;
const hasExceededRate = now - previousUpdate >= timerConfig.notificationRate; const hasExceededRate = now - previousUpdate >= timerConfig.notificationRate;
return isClockBehind || hasExceededRate; return isClockBehind || hasExceededRate;