-
Notifications
You must be signed in to change notification settings - Fork 133
/
Copy pathupdatable-timer.ts
63 lines (55 loc) · 1.93 KB
/
updatable-timer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// TODO - incorporate into the starter
import { defineSignal, defineQuery, setHandler, condition, log } from '@temporalio/workflow';
export const setDeadlineSignal = defineSignal<[number]>('setDeadline');
export const timeLeftQuery = defineQuery<number>('timeLeft');
// @@@SNIPSTART typescript-updatable-timer-impl
// usage
export async function countdownWorkflow(): Promise<void> {
const target = Date.now() + 24 * 60 * 60 * 1000; // 1 day!!!
const timer = new UpdatableTimer(target);
log.info('timer set', { target: new Date(target) });
setHandler(setDeadlineSignal, (deadline) => {
// send in new deadlines via Signal
timer.deadline = deadline;
log.info('timer updated', { target: new Date(deadline) });
});
setHandler(timeLeftQuery, () => timer.deadline - Date.now());
await timer; // if you send in a signal with a new time, this timer will resolve earlier!
log.info('countdown done!');
}
// implementation
export class UpdatableTimer implements PromiseLike<void> {
deadlineUpdated = false;
#deadline: number;
readonly promise: Promise<void>;
constructor(deadline: number) {
this.#deadline = deadline;
this.promise = this.run();
this.promise.catch(() => {
// avoid unhandled rejection
});
}
private async run(): Promise<void> {
/* eslint-disable no-constant-condition */
while (true) {
this.deadlineUpdated = false;
if (!(await condition(() => this.deadlineUpdated, this.#deadline - Date.now()))) {
break;
}
}
}
then<TResult1 = void, TResult2 = never>(
onfulfilled?: (value: void) => TResult1 | PromiseLike<TResult1>,
onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>,
): PromiseLike<TResult1 | TResult2> {
return this.promise.then(onfulfilled, onrejected);
}
set deadline(value: number) {
this.#deadline = value;
this.deadlineUpdated = true;
}
get deadline(): number {
return this.#deadline;
}
}
// @@@SNIPEND