fix(tasks): close background task review findings
This commit is contained in:
@@ -83,6 +83,8 @@ interface TrackedTask {
|
||||
markSettled: () => void
|
||||
/** Live {@link TaskService.wait} calls — a settlement with waiters marks the task reported. */
|
||||
waiters: number
|
||||
/** Removable resolvers for live waits; timeout/abort unregister before the task settles. */
|
||||
waitResolvers: Set<() => void>
|
||||
}
|
||||
|
||||
/** True for the three terminal {@link TaskStatus} values. */
|
||||
@@ -169,6 +171,7 @@ export class TaskService extends Service {
|
||||
settled,
|
||||
markSettled,
|
||||
waiters: 0,
|
||||
waitResolvers: new Set(),
|
||||
}
|
||||
this.store.set(id, task)
|
||||
|
||||
@@ -276,8 +279,10 @@ export class TaskService extends Service {
|
||||
* has already settled: settlement saw this live waiter and suppressed the
|
||||
* completion notice on its behalf, so the wait still resolves and delivers
|
||||
* the terminal snapshot it owes (an abort must never leave a finished task
|
||||
* both unreported and notice-suppressed). Throws for an unknown id, a task
|
||||
* owned by another session, or a non-positive timeout.
|
||||
* both unreported and notice-suppressed). Each live wait uses a removable
|
||||
* resolver that timeout/abort detaches, so a long-running task does not
|
||||
* retain expired waits. Throws for an unknown id, a task owned by another
|
||||
* session, or a non-positive timeout.
|
||||
* @param id - the task to wait for.
|
||||
* @param timeoutMs - max wait in milliseconds (positive, finite; the surface caps it).
|
||||
* @param caller - the waiting agent, checked against the task's owner.
|
||||
@@ -313,7 +318,13 @@ export class TaskService extends Service {
|
||||
// the wait. `using` clears the timer on every exit path.
|
||||
using d = deadline(signal, timeoutMs, TASK_WAIT_TIMEOUT)
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const onSettled = (): void => {
|
||||
task.waitResolvers.delete(onSettled)
|
||||
d.signal.removeEventListener('abort', onAbort)
|
||||
resolve()
|
||||
}
|
||||
const onAbort = (): void => {
|
||||
task.waitResolvers.delete(onSettled)
|
||||
if (timeoutOf(d.signal, TASK_WAIT_TIMEOUT) !== undefined) {
|
||||
resolve()
|
||||
} else if (isTerminal(task.status)) {
|
||||
@@ -325,11 +336,8 @@ export class TaskService extends Service {
|
||||
reject(new Error('wait aborted'))
|
||||
}
|
||||
}
|
||||
task.waitResolvers.add(onSettled)
|
||||
d.signal.addEventListener('abort', onAbort, { once: true })
|
||||
void task.settled.then(() => {
|
||||
d.signal.removeEventListener('abort', onAbort)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
} finally {
|
||||
uncount()
|
||||
@@ -437,6 +445,9 @@ export class TaskService extends Service {
|
||||
}
|
||||
}
|
||||
}
|
||||
const waitResolvers = [...task.waitResolvers]
|
||||
task.waitResolvers.clear()
|
||||
for (const resolveWait of waitResolvers) resolveWait()
|
||||
task.markSettled()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user