refactor: unify queueing and normalize telegram slack flows

This commit is contained in:
Peter Steinberger
2026-03-02 20:55:10 +00:00
parent 320920d523
commit 3a08e69a05
21 changed files with 627 additions and 266 deletions

View File

@@ -1,9 +1,11 @@
import { KeyedAsyncQueue } from "../../plugin-sdk/keyed-async-queue.js";
export class SessionActorQueue {
private readonly tailBySession = new Map<string, Promise<void>>();
private readonly queue = new KeyedAsyncQueue();
private readonly pendingBySession = new Map<string, number>();
getTailMapForTesting(): Map<string, Promise<void>> {
return this.tailBySession;
return this.queue.getTailMapForTesting();
}
getTotalPendingCount(): number {
@@ -19,35 +21,18 @@ export class SessionActorQueue {
}
async run<T>(actorKey: string, op: () => Promise<T>): Promise<T> {
const previous = this.tailBySession.get(actorKey) ?? Promise.resolve();
this.pendingBySession.set(actorKey, (this.pendingBySession.get(actorKey) ?? 0) + 1);
let release: () => void = () => {};
const marker = new Promise<void>((resolve) => {
release = resolve;
return this.queue.enqueue(actorKey, op, {
onEnqueue: () => {
this.pendingBySession.set(actorKey, (this.pendingBySession.get(actorKey) ?? 0) + 1);
},
onSettle: () => {
const pending = (this.pendingBySession.get(actorKey) ?? 1) - 1;
if (pending <= 0) {
this.pendingBySession.delete(actorKey);
} else {
this.pendingBySession.set(actorKey, pending);
}
},
});
const queuedTail = previous
.catch(() => {
// Keep actor queue alive after an operation failure.
})
.then(() => marker);
this.tailBySession.set(actorKey, queuedTail);
await previous.catch(() => {
// Previous failures should not block newer commands.
});
try {
return await op();
} finally {
const pending = (this.pendingBySession.get(actorKey) ?? 1) - 1;
if (pending <= 0) {
this.pendingBySession.delete(actorKey);
} else {
this.pendingBySession.set(actorKey, pending);
}
release();
if (this.tailBySession.get(actorKey) === queuedTail) {
this.tailBySession.delete(actorKey);
}
}
}
}