commit b79efd6f9786ac59089571d18ce88fd262b0b0a1
parent fddafb9fc9b6934b8840e1487eef1c28dd6b1502
Author: Florian Dold <dold@taler.net>
Date: Tue, 21 Jul 2026 11:02:41 +0200
util: settle pending waits when a timer group is stopped
Stopping a group clears the armed handles and after() then drops any new
timer, so every wait in flight at shutdown stayed suspended forever and
every later one hung.
Diffstat:
1 file changed, 24 insertions(+), 8 deletions(-)
diff --git a/packages/taler-util/src/timer.ts b/packages/taler-util/src/timer.ts
@@ -145,6 +145,13 @@ export class TimerGroup {
private readonly timerMap: { [index: number]: TimerHandle } = {};
+ /**
+ * Resolvers of pending resolveAfter() calls. Stopping the group clears the
+ * armed timers, so without these the waits they belong to would never
+ * settle and their callers would stay suspended forever.
+ */
+ private readonly pendingWaits = new Set<(fired: boolean) => void>();
+
private idGen = 1;
constructor(public readonly timerApi: TimerAPI) {}
@@ -158,20 +165,32 @@ export class TimerGroup {
this.timerMap[x].clear();
delete this.timerMap[x];
}
+ const waits = [...this.pendingWaits];
+ this.pendingWaits.clear();
+ for (const w of waits) {
+ w(false);
+ }
}
resolveAfter(
delayMs: Duration,
cancellationToken?: CancellationToken,
): Promise<boolean> {
+ if (this.stopped) {
+ return Promise.resolve(false);
+ }
return new Promise<boolean>((resolve, reject) => {
let unregisterCt: (() => void) | undefined;
let timerHandle: TimerHandle | undefined;
+ const settle = (fired: boolean): void => {
+ this.pendingWaits.delete(settle);
+ unregisterCt?.();
+ timerHandle?.clear();
+ resolve(fired);
+ };
+ this.pendingWaits.add(settle);
if (cancellationToken != null) {
- unregisterCt = cancellationToken.onCancelled(() => {
- timerHandle?.clear();
- resolve(false);
- });
+ unregisterCt = cancellationToken.onCancelled(() => settle(false));
}
// onCancelled fires synchronously for an already-cancelled token, so
// the promise may have settled; a timer scheduled now is an orphan.
@@ -179,10 +198,7 @@ export class TimerGroup {
return;
}
if (delayMs.d_ms !== "forever") {
- timerHandle = this.after(delayMs.d_ms, () => {
- unregisterCt?.();
- resolve(true);
- });
+ timerHandle = this.after(delayMs.d_ms, () => settle(true));
}
});
}