taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit cab77b9dae0c74c299cd3c60ba2b17257bca27c6
parent ac27eec581d2dce1ab9d7ee6c9f1b96a6718ddf0
Author: Florian Dold <florian@dold.me>
Date:   Wed,  3 Jun 2026 21:58:43 +0200

wallet-core: fix shepherd task cancellation

Diffstat:
Mpackages/taler-wallet-core/src/shepherd.ts | 25++++++++++++++++++++-----
Mpackages/taler-wallet-core/src/wallet.ts | 1+
2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/packages/taler-wallet-core/src/shepherd.ts b/packages/taler-wallet-core/src/shepherd.ts @@ -137,6 +137,11 @@ interface ShepherdInfo { interruptWait: () => void; taskState: TaskState; + + /** + * Unique numeric identifier for the shepherd. + */ + shepId: number; } /** @@ -198,6 +203,8 @@ export class TaskSchedulerImpl implements TaskScheduler { isRunning: boolean = false; + private shepCounter = 1; + constructor(private ws: InternalWalletState) {} private async loadTasksFromDb(): Promise<void> { @@ -304,7 +311,6 @@ export class TaskSchedulerImpl implements TaskScheduler { logger.info(`reloading shepherd with ${tasksIds.length} existing tasks`); for (const taskId of tasksIds) { this.stopShepherdTask(taskId); - this.sheps.delete(taskId); } await this.loadTasksFromDb(); } @@ -333,22 +339,31 @@ export class TaskSchedulerImpl implements TaskScheduler { logger.trace( `Waiting for old task to complete the loop in cancel mode ${taskId}`, ); - await oldShep.latch; - logger.trace(`Old task ${taskId} completed in cancel mode`); + oldShep.cts.cancel(); } - logger.trace(`Creating new shepherd for ${taskId}`); const newShep: ShepherdInfo = { cts: CancellationToken.create(), taskState: TaskState.Running, interruptWait: () => undefined, + shepId: this.shepCounter++, }; + logger.trace( + `Creating new shepherd for ${taskId} with shepId=${newShep.shepId}`, + ); this.sheps.set(taskId, newShep); + if (oldShep) { + await oldShep.latch; + logger.trace(`Old task ${taskId} completed in cancel mode`); + } try { newShep.latch = this.internalShepherdTask(taskId, newShep); await newShep.latch; } finally { logger.trace(`Done shepherding ${taskId}`); - this.sheps.delete(taskId); + newShep.cts.cancel(); + if (this.sheps.get(taskId)?.shepId === newShep.shepId) { + this.sheps.delete(taskId); + } this.iterCond.trigger(); } } diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts @@ -1687,6 +1687,7 @@ async function handleShutdown( wex: WalletExecutionContext, _req: EmptyObject, ): Promise<EmptyObject> { + logger.info(`Shutdown requested`); wex.ws.stop(); return {}; }