fix(gateway): recover stale session lanes

This commit is contained in:
Peter Steinberger
2026-04-28 20:36:40 +01:00
parent 933c7968dc
commit c500e8704f
14 changed files with 729 additions and 5 deletions

View File

@@ -51,6 +51,15 @@ type LaneState = {
generation: number;
};
export type CommandLaneSnapshot = {
lane: string;
queuedCount: number;
activeCount: number;
maxConcurrent: number;
draining: boolean;
generation: number;
};
type ActiveTaskWaiter = {
activeTaskIds: Set<number>;
resolve: (value: { drained: boolean }) => void;
@@ -287,6 +296,29 @@ export function getQueueSize(lane: string = CommandLane.Main) {
return getLaneDepth(state);
}
export function getCommandLaneSnapshot(lane: string = CommandLane.Main): CommandLaneSnapshot {
const resolved = normalizeLane(lane);
const state = getQueueState().lanes.get(resolved);
if (!state) {
return {
lane: resolved,
queuedCount: 0,
activeCount: 0,
maxConcurrent: 1,
draining: false,
generation: 0,
};
}
return {
lane: resolved,
queuedCount: state.queue.length,
activeCount: state.activeTaskIds.size,
maxConcurrent: state.maxConcurrent,
draining: state.draining,
generation: state.generation,
};
}
export function getTotalQueueSize() {
let total = 0;
for (const s of getQueueState().lanes.values()) {
@@ -309,6 +341,28 @@ export function clearCommandLane(lane: string = CommandLane.Main) {
return removed;
}
/**
* Force a single lane back to idle and immediately pump any queued entries.
* Used only by recovery paths after the owner has already attempted to abort
* the active work; stale completions from the previous generation are ignored.
*/
export function resetCommandLane(lane: string = CommandLane.Main): number {
const cleaned = normalizeLane(lane);
const state = getQueueState().lanes.get(cleaned);
if (!state) {
return 0;
}
const released = state.activeTaskIds.size;
state.generation += 1;
state.activeTaskIds.clear();
state.draining = false;
if (state.queue.length > 0) {
drainLane(cleaned);
}
notifyActiveTaskWaiters();
return released;
}
/**
* Test-only hard reset that discards all queue state, including preserved
* queued work from previous generations. Use this when a suite needs an