Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

177 lines
5.0 KiB
TypeScript

export interface AbortableSingleFlightResult<TValue> {
readonly promise: Promise<TValue>;
readonly shared: boolean;
}
export interface AbortableSingleFlightStartContext {
readonly signal: AbortSignal;
abort(reason?: unknown): void;
}
type SingleFlightState = "running" | "settled" | "aborted";
interface SingleFlightEntry<TValue> {
readonly abortController: AbortController;
readonly consumers: Set<symbol>;
rejectStarted?: (reason?: unknown) => void;
promise: Promise<TValue>;
state: SingleFlightState;
}
/**
* Shares one abortable operation per key while keeping caller cancellation
* independent. The underlying operation is aborted only when its final caller
* leaves, and that entry is evicted before aborting so an immediate retry can
* never acquire the aborted operation.
*/
export class AbortableSingleFlight<TKey, TValue> {
private readonly entries = new Map<TKey, SingleFlightEntry<TValue>>();
acquire(
key: TKey,
start: (context: AbortableSingleFlightStartContext) => Promise<TValue>,
signal?: AbortSignal
): AbortableSingleFlightResult<TValue> {
if (signal?.aborted) {
return {
promise: Promise.reject(createAbortError()),
shared: false
};
}
let entry = this.entries.get(key);
let shared = true;
if (
!entry ||
entry.state !== "running" ||
entry.abortController.signal.aborted
) {
shared = false;
entry = this.createEntry(key, start);
}
return {
promise: this.subscribe(key, entry, signal),
shared
};
}
abortAll(reason?: unknown): void {
const entries = [...this.entries.values()];
this.entries.clear();
for (const entry of entries) {
this.abortEntry(undefined, entry, reason);
}
}
private createEntry(
key: TKey,
start: (context: AbortableSingleFlightStartContext) => Promise<TValue>
): SingleFlightEntry<TValue> {
let resolveStarted!: (value: TValue | PromiseLike<TValue>) => void;
let rejectStarted!: (reason?: unknown) => void;
const started = new Promise<TValue>((resolve, reject) => {
resolveStarted = resolve;
rejectStarted = reject;
});
const abortController = new AbortController();
const entry: SingleFlightEntry<TValue> = {
abortController,
consumers: new Set(),
promise: Promise.resolve() as Promise<TValue>,
state: "running"
};
entry.rejectStarted = rejectStarted;
entry.promise = started
.then((value) => {
if (abortController.signal.aborted) {
throw abortController.signal.reason ?? createAbortError();
}
return value;
})
.finally(() => {
entry.state = "settled";
if (this.entries.get(key) === entry) {
this.entries.delete(key);
}
});
this.entries.set(key, entry);
try {
Promise.resolve(
start({
signal: abortController.signal,
abort: (reason) => this.abortEntry(key, entry, reason)
})
).then(resolveStarted, rejectStarted);
} catch (error) {
rejectStarted(error);
}
// If every consumer leaves before the operation settles, the shared
// promise still needs an explicit rejection handler to avoid an unhandled
// rejection while the abandoned operation unwinds.
entry.promise.catch(() => undefined);
return entry;
}
private subscribe(
key: TKey,
entry: SingleFlightEntry<TValue>,
signal?: AbortSignal
): Promise<TValue> {
const consumer = Symbol("single-flight-consumer");
entry.consumers.add(consumer);
return new Promise<TValue>((resolve, reject) => {
let finished = false;
const finish = (settle: () => void, abortWhenUnused: boolean): void => {
if (finished) {
return;
}
finished = true;
signal?.removeEventListener("abort", handleAbort);
entry.consumers.delete(consumer);
if (abortWhenUnused && entry.consumers.size === 0) {
this.abortEntry(key, entry);
}
settle();
};
const handleAbort = (): void => {
finish(() => reject(createAbortError()), true);
};
if (signal?.aborted) {
handleAbort();
return;
}
signal?.addEventListener("abort", handleAbort, { once: true });
entry.promise.then(
(value) => finish(() => resolve(value), false),
(error) => finish(() => reject(error), false)
);
});
}
private abortEntry(
key: TKey | undefined,
entry: SingleFlightEntry<TValue>,
reason?: unknown
): void {
if (entry.state !== "running") {
return;
}
entry.state = "aborted";
if (key !== undefined && this.entries.get(key) === entry) {
this.entries.delete(key);
}
const abortReason = reason ?? createAbortError();
entry.rejectStarted?.(abortReason);
entry.abortController.abort(abortReason);
}
}
function createAbortError(): Error {
const error = new Error("Single-flight request was aborted");
error.name = "AbortError";
return error;
}