backend-test-utils: abort mock tasks on shutdown

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2025-08-18 11:32:38 +02:00
parent dffaf708e9
commit 6883a90b29
2 changed files with 51 additions and 1 deletions
@@ -205,4 +205,39 @@ describe('MockSchedulerService', () => {
expect(taskFn).toHaveBeenCalled();
await expect(isDone()).resolves.toBe(true);
});
it('should abort tasks when shutting down', async () => {
let taskSignal: AbortSignal | undefined;
const backend = await startTestBackend({
features: [
mockServices.scheduler.factory({
includeManualTasksOnStartup: true,
includeInitialDelayedTasksOnStartup: true,
}),
createBackendPlugin({
pluginId: 'tester',
register(reg) {
reg.registerInit({
deps: { scheduler: coreServices.scheduler },
async init({ scheduler }) {
scheduler.scheduleTask({
...baseOpts,
id: 'test-plain',
fn: async signal => {
taskSignal = signal;
},
});
},
});
},
}),
],
});
expect(taskSignal).toBeDefined();
expect(taskSignal?.aborted).toBe(false);
await backend.stop();
expect(taskSignal?.aborted).toBe(true);
});
});
@@ -31,6 +31,7 @@ export class MockSchedulerService implements SchedulerService {
SchedulerServiceTaskInvocationDefinition &
SchedulerServiceTaskScheduleDefinition & {
descriptor: SchedulerServiceTaskDescriptor;
abortControllers: AbortController[];
}
>();
readonly #runningTasks = new Set<string>();
@@ -57,6 +58,9 @@ export class MockSchedulerService implements SchedulerService {
});
});
}
lifecycle.addShutdownHook(async () => {
await this.#shutdownAllTasks();
});
return this;
},
});
@@ -87,6 +91,7 @@ export class MockSchedulerService implements SchedulerService {
scope: task.scope ?? 'global',
settings: { version: 1 },
},
abortControllers: [],
});
}
@@ -100,7 +105,9 @@ export class MockSchedulerService implements SchedulerService {
}
this.#runningTasks.add(id);
try {
await task.fn(new AbortController().signal);
const abortController = new AbortController();
task.abortControllers.push(abortController);
await task.fn(abortController.signal);
this.#deferredTaskCompletions.get(id)?.resolve();
} catch (error) {
this.#deferredTaskCompletions.get(id)?.reject(error);
@@ -144,6 +151,14 @@ export class MockSchedulerService implements SchedulerService {
await Promise.all(selectedTaskIds.map(id => this.triggerTask(id)));
}
async #shutdownAllTasks() {
for (const task of this.#tasks.values()) {
for (const abortController of task.abortControllers) {
abortController.abort();
}
}
}
/**
* Wait for the task with the given ID to complete.
*