@parall/agent-core 1.45.0 → 1.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/channel-capability.d.ts +2 -0
- package/dist/channel-capability.d.ts.map +1 -1
- package/dist/channel-capability.js +15 -0
- package/dist/dispatch-adapter.d.ts +9 -0
- package/dist/dispatch-adapter.d.ts.map +1 -1
- package/dist/event-format.d.ts.map +1 -1
- package/dist/event-format.js +27 -7
- package/dist/fork-session-finalizer.d.ts +65 -0
- package/dist/fork-session-finalizer.d.ts.map +1 -0
- package/dist/fork-session-finalizer.js +70 -0
- package/dist/gateway-base.d.ts +47 -0
- package/dist/gateway-base.d.ts.map +1 -1
- package/dist/gateway-base.js +457 -200
- package/dist/gateway-lane-flow.d.ts.map +1 -1
- package/dist/gateway-lane-flow.js +13 -7
- package/dist/http-keepalive.d.ts +4 -0
- package/dist/http-keepalive.d.ts.map +1 -0
- package/dist/http-keepalive.js +33 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/session-lifecycle.d.ts +198 -0
- package/dist/session-lifecycle.d.ts.map +1 -0
- package/dist/session-lifecycle.js +446 -0
- package/dist/skills/parall-clips.d.ts +1 -1
- package/dist/skills/parall-clips.d.ts.map +1 -1
- package/dist/skills/parall-clips.js +3 -0
- package/dist/step-persister.d.ts +66 -0
- package/dist/step-persister.d.ts.map +1 -0
- package/dist/step-persister.js +116 -0
- package/dist/step-retry-queue.d.ts +91 -0
- package/dist/step-retry-queue.d.ts.map +1 -0
- package/dist/step-retry-queue.js +259 -0
- package/package.json +3 -2
- package/src/channel-capability.ts +16 -0
- package/src/dispatch-adapter.ts +10 -0
- package/src/event-format.ts +27 -7
- package/src/fork-session-finalizer.ts +122 -0
- package/src/gateway-base.ts +487 -255
- package/src/gateway-lane-flow.ts +12 -7
- package/src/http-keepalive.ts +36 -0
- package/src/index.ts +6 -0
- package/src/session-lifecycle.ts +552 -0
- package/src/skills/parall-clips.ts +3 -0
- package/src/step-persister.ts +161 -0
- package/src/step-retry-queue.ts +296 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-lane-flow.d.ts","sourceRoot":"","sources":["../src/gateway-lane-flow.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"gateway-lane-flow.d.ts","sourceRoot":"","sources":["../src/gateway-lane-flow.ts"],"names":[],"mappings":"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"}
|
|
@@ -218,16 +218,23 @@ export async function settleDrainedTypedGroup(host, events, ids, turnErrored) {
|
|
|
218
218
|
return;
|
|
219
219
|
}
|
|
220
220
|
// The legacy ack BY ID, never by source — task siblings share a source
|
|
221
|
-
// pair, and a by-source ack would sweep the undispatched one. Awaited
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
// self-rejected
|
|
221
|
+
// pair, and a by-source ack would sweep the undispatched one. Awaited, and
|
|
222
|
+
// the dedupe claim is freed on EVERY outcome: a claim's lifetime is the
|
|
223
|
+
// buffer stay (#1149). On failure the row is still pending and its retry
|
|
224
|
+
// must not be self-rejected; on success the row is terminal — but a
|
|
225
|
+
// shared-key sibling WorkItem (task assign+update fetch the same
|
|
226
|
+
// `task:updated_at` pair) must not be rejected by a leftover claim either.
|
|
225
227
|
const legacyAckFrom = async (start) => {
|
|
226
228
|
for (const [j, id] of ids.slice(start).entries()) {
|
|
227
229
|
try {
|
|
228
230
|
await host.opts.client.ackDispatchByID(host.opts.config.org_id, id);
|
|
229
231
|
}
|
|
230
232
|
catch {
|
|
233
|
+
// Transient ack failure: the row stays live server-side and its
|
|
234
|
+
// re-drive re-converges — keep settling the REST of the group (a
|
|
235
|
+
// propagated error would strand every later id's retained claim).
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
231
238
|
clearTypedDedupeForEvent(host, events[start + j]);
|
|
232
239
|
}
|
|
233
240
|
}
|
|
@@ -246,9 +253,8 @@ export async function settleDrainedTypedGroup(host, events, ids, turnErrored) {
|
|
|
246
253
|
await legacyAckFrom(i);
|
|
247
254
|
return;
|
|
248
255
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
256
|
+
// Freed on every outcome — see legacyAckFrom's contract note.
|
|
257
|
+
clearTypedDedupeForEvent(host, events[i]);
|
|
252
258
|
}
|
|
253
259
|
}
|
|
254
260
|
/** Failure backoff pacing for typed dispatch retries (base 2s, cap 5min). */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-keepalive.d.ts","sourceRoot":"","sources":["../src/http-keepalive.ts"],"names":[],"mappings":"AAsBA,wBAAgB,sBAAsB,CAAC,IAAI,CAAC,EAAE;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAanF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Agent, setGlobalDispatcher } from 'undici';
|
|
2
|
+
/**
|
|
3
|
+
* Keep bridge→api HTTP connections long-lived.
|
|
4
|
+
*
|
|
5
|
+
* Node's built-in fetch closes idle pooled connections after ~4s when the
|
|
6
|
+
* server sends no Keep-Alive hint (our NLB+Envoy edge sends none), so any two
|
|
7
|
+
* bridge API calls spaced more than a few seconds apart pay a fresh TCP+TLS
|
|
8
|
+
* handshake. On a degraded long-haul link that handshake is exactly what
|
|
9
|
+
* fails — established connections (the WS, the runtime's own model stream)
|
|
10
|
+
* ride through such windows while every bridge call times out (2026-07-10:
|
|
11
|
+
* step creation losses). A 2-minute idle timeout keeps one warm connection
|
|
12
|
+
* across an active turn's step cadence, comfortably below the NLB's 350s
|
|
13
|
+
* idle cutoff.
|
|
14
|
+
*
|
|
15
|
+
* Uses undici's global-dispatcher registry, which Node's built-in fetch
|
|
16
|
+
* shares (verified on Node 22 / undici 7) — so this covers every fetch in
|
|
17
|
+
* the process: ParallClient, lane-ledger heartbeats, OTLP export.
|
|
18
|
+
* Node-only; call once from a bridge/daemon entrypoint before any fetch.
|
|
19
|
+
*/
|
|
20
|
+
let installed = false;
|
|
21
|
+
export function configureHttpKeepAlive(opts) {
|
|
22
|
+
// Idempotent: a second call (e.g. a process hosting several bridge
|
|
23
|
+
// entrypoints) must not replace — and leak — the already-installed Agent.
|
|
24
|
+
if (installed)
|
|
25
|
+
return;
|
|
26
|
+
installed = true;
|
|
27
|
+
const keepAliveTimeout = opts?.keepAliveTimeoutMs ?? 120_000;
|
|
28
|
+
setGlobalDispatcher(new Agent({
|
|
29
|
+
keepAliveTimeout,
|
|
30
|
+
// Also cap the server-hinted value: never idle past the edge's cutoff.
|
|
31
|
+
keepAliveMaxTimeout: keepAliveTimeout,
|
|
32
|
+
}));
|
|
33
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export * from './bridge-workspace.js';
|
|
|
11
11
|
export * from './dispatch-adapter.js';
|
|
12
12
|
export { createLogger, childLogger } from './logger.js';
|
|
13
13
|
export * from './gateway-base.js';
|
|
14
|
+
export { configureHttpKeepAlive } from './http-keepalive.js';
|
|
14
15
|
export * from './platform-config.js';
|
|
15
16
|
export * from './channel-capability.js';
|
|
16
17
|
export * from './channel-token.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACvF,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACvF,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAM7D,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,12 @@ export * from './bridge-workspace.js';
|
|
|
10
10
|
export * from './dispatch-adapter.js';
|
|
11
11
|
export { createLogger, childLogger } from './logger.js';
|
|
12
12
|
export * from './gateway-base.js';
|
|
13
|
+
export { configureHttpKeepAlive } from './http-keepalive.js';
|
|
14
|
+
// StepPersister / StepRetryQueue / SessionLifecycleCoordinator /
|
|
15
|
+
// ForkSessionFinalizer are internal gateway collaborators — deliberately NOT
|
|
16
|
+
// re-exported from the package root (no external consumer; a root export
|
|
17
|
+
// would become an accidental long-term compat promise). Tests import their
|
|
18
|
+
// built modules directly (e.g. `../dist/step-retry-queue.js`).
|
|
13
19
|
export * from './platform-config.js';
|
|
14
20
|
export * from './channel-capability.js';
|
|
15
21
|
export * from './channel-token.js';
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionLifecycleCoordinator — the single entry point for session status
|
|
3
|
+
* writes (active / idle / closed).
|
|
4
|
+
*
|
|
5
|
+
* SCOPE — this is a **process-local mitigation**, not a distributed fence.
|
|
6
|
+
* It serializes and orders the lifecycle writes THIS process issues. It does
|
|
7
|
+
* NOT order across processes, and it cannot fix a write that times out
|
|
8
|
+
* client-side but lands server-side later, nor an old turn's step retry
|
|
9
|
+
* landing during a new turn. The structural fix is a server-side turn fence
|
|
10
|
+
* (design tracked in #1879 — durable step outbox + turn fence); until that
|
|
11
|
+
* ships, this closes the in-process interleavings that produced the
|
|
12
|
+
* 2026-07-13 repro.
|
|
13
|
+
*
|
|
14
|
+
* The gateway used to fire active and idle PATCHes independently
|
|
15
|
+
* (fire-and-forget + detached retries). Two independent HTTP requests have
|
|
16
|
+
* no ordering: turn 1's in-flight idle could land AFTER turn 2's active and
|
|
17
|
+
* demote a running session — an epoch check on retry TIMERS cannot cancel a
|
|
18
|
+
* request already on the wire. The coordinator closes that class by being a
|
|
19
|
+
* serialized desired-state reconciler:
|
|
20
|
+
*
|
|
21
|
+
* - Per session it stores only the LATEST desired state plus a monotonic
|
|
22
|
+
* generation (bumped by beginTurn and closeSession).
|
|
23
|
+
* - At most ONE lifecycle write is in flight per session; when it settles
|
|
24
|
+
* the loop re-reads the latest desired state and reconciles — so a
|
|
25
|
+
* begin(turn N+1), or a closeSession, that arrives while an earlier write
|
|
26
|
+
* is in flight simply waits for it to settle and is written AFTER it.
|
|
27
|
+
* - finishTurn carries the TurnHandle from its beginTurn; a stale handle
|
|
28
|
+
* (generation superseded) is ignored outright.
|
|
29
|
+
* - Retries re-run the reconcile loop against the LATEST desired state —
|
|
30
|
+
* they never replay a captured command, so a pending idle retry is
|
|
31
|
+
* naturally superseded by a new turn.
|
|
32
|
+
* - Errors are CLASSIFIED (ports, defaults are conservative): transient →
|
|
33
|
+
* bounded backoff; permanent (4xx) → warn + abandon that desired state (a
|
|
34
|
+
* later turn retries with a fresh generation); session-stale (the server
|
|
35
|
+
* considers the session terminal) → drop the session, never write again.
|
|
36
|
+
* - beginTurn / closeSession resolve once one write attempt covering their
|
|
37
|
+
* generation has SETTLED (success or failure — bounded by the write's own
|
|
38
|
+
* timeout, plus at most one in-flight predecessor). The gateway awaits
|
|
39
|
+
* beginTurn before persisting the turn's first AgentStep, so a reused idle
|
|
40
|
+
* session is reconciled to active before steps arrive and the server's
|
|
41
|
+
* presence guard cannot swallow the turn's activity. A failed active write
|
|
42
|
+
* warns and lets the step flow continue.
|
|
43
|
+
* - closeSession's first settle carries a STRUCTURED outcome (`closed` /
|
|
44
|
+
* `stale` / `retrying` / `permanent_failure` / `disposed`) plus a
|
|
45
|
+
* `terminal` promise that resolves when the close reaches a terminal fate
|
|
46
|
+
* — a caller holding cleanup behind the close (ForkSessionFinalizer) can
|
|
47
|
+
* keep ownership through `retrying` instead of mistaking "one attempt
|
|
48
|
+
* settled" for "close completed".
|
|
49
|
+
* - Entries are RECLAIMED (no unbounded Map growth on long-lived daemons):
|
|
50
|
+
* dropSession removes the entry immediately when idle, or at the end of an
|
|
51
|
+
* in-flight write; a `closed` that landed OR failed permanently reclaims
|
|
52
|
+
* too — the permanent failure is not hidden by the reclaim, it is reported
|
|
53
|
+
* through the close's outcome/terminal before the entry goes away.
|
|
54
|
+
* - dispose() is absorbing: every later public command is a no-op that never
|
|
55
|
+
* re-creates an entry, issues a write, or arms a timer.
|
|
56
|
+
*
|
|
57
|
+
* The write port is infrastructure (ParallClient.updateAgentSession);
|
|
58
|
+
* retries, generations, error classification and the state machine live here.
|
|
59
|
+
*/
|
|
60
|
+
export type SessionStatusPayload = {
|
|
61
|
+
status: 'active';
|
|
62
|
+
trigger_message_id?: string;
|
|
63
|
+
} | {
|
|
64
|
+
status: 'idle';
|
|
65
|
+
} | {
|
|
66
|
+
status: 'closed';
|
|
67
|
+
};
|
|
68
|
+
export type TurnHandle = {
|
|
69
|
+
sessionId: string;
|
|
70
|
+
generation: number;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Terminal fate of a closeSession: `closed` — the write landed; `stale` —
|
|
74
|
+
* the server already considers the session terminal (equivalent outcome for
|
|
75
|
+
* the caller); `permanent_failure` — a 4xx or retry exhaustion; the close
|
|
76
|
+
* will never be written and the server-side session may be left non-closed;
|
|
77
|
+
* `disposed` — the coordinator shut down before the close settled.
|
|
78
|
+
*/
|
|
79
|
+
export type SessionCloseOutcome = 'closed' | 'stale' | 'permanent_failure' | 'disposed';
|
|
80
|
+
/** First-settle view: `retrying` means a transient failure settled the first
|
|
81
|
+
* bounded attempt and background reconciliation continues — await `terminal`
|
|
82
|
+
* for the eventual fate. */
|
|
83
|
+
export type SessionCloseSettle = SessionCloseOutcome | 'retrying';
|
|
84
|
+
export type SessionCloseResult = {
|
|
85
|
+
/** Outcome of the first bounded settle (one write attempt covering the close). */
|
|
86
|
+
outcome: SessionCloseSettle;
|
|
87
|
+
/**
|
|
88
|
+
* Resolves when the close reaches a terminal state. Already resolved (to
|
|
89
|
+
* `outcome`) unless `outcome === 'retrying'`.
|
|
90
|
+
*/
|
|
91
|
+
terminal: Promise<SessionCloseOutcome>;
|
|
92
|
+
};
|
|
93
|
+
export type SessionLifecycleScheduler = {
|
|
94
|
+
setTimeout(fn: () => void, ms: number): unknown;
|
|
95
|
+
clearTimeout(timer: unknown): void;
|
|
96
|
+
};
|
|
97
|
+
export type SessionLifecycleOpts = {
|
|
98
|
+
write: (sessionId: string, payload: SessionStatusPayload) => Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Transient failure worth retrying (timeout / network / 5xx). Anything
|
|
101
|
+
* else is treated as permanent: warn + abandon (no retry loop against a
|
|
102
|
+
* 400/401/403/404). Default: nothing is retryable — callers that want
|
|
103
|
+
* retries must classify.
|
|
104
|
+
*/
|
|
105
|
+
isRetryable?: (err: unknown) => boolean;
|
|
106
|
+
/**
|
|
107
|
+
* The server considers this session terminal (409 SESSION_NOT_LIVE /
|
|
108
|
+
* INVALID_TRANSITION). The session is dropped — no further lifecycle
|
|
109
|
+
* writes, ever. Default: never stale.
|
|
110
|
+
*/
|
|
111
|
+
isSessionStale?: (err: unknown) => boolean;
|
|
112
|
+
log?: {
|
|
113
|
+
warn: (msg: string) => void;
|
|
114
|
+
};
|
|
115
|
+
/** Test port; default wraps global timers and unrefs them. */
|
|
116
|
+
scheduler?: SessionLifecycleScheduler;
|
|
117
|
+
/** Reconcile retry backoff. Default 5s→15s→45s→135s→405s (~10 min). */
|
|
118
|
+
retryDelaysMs?: number[];
|
|
119
|
+
};
|
|
120
|
+
export declare class SessionLifecycleCoordinator {
|
|
121
|
+
private readonly opts;
|
|
122
|
+
private readonly sessions;
|
|
123
|
+
private readonly scheduler;
|
|
124
|
+
private readonly retryDelays;
|
|
125
|
+
private nextGeneration;
|
|
126
|
+
private disposed;
|
|
127
|
+
constructor(opts: SessionLifecycleOpts);
|
|
128
|
+
/** Sessions currently tracked — reclaimed entries are gone (leak probe). */
|
|
129
|
+
trackedSessions(): number;
|
|
130
|
+
/**
|
|
131
|
+
* Declare a new turn. Resolves once one write attempt covering this turn's
|
|
132
|
+
* generation has settled (bounded: at most one in-flight predecessor plus
|
|
133
|
+
* one active write, each bounded by the write port's own timeout). Always
|
|
134
|
+
* resolves — a failed active write is warned and reconciled in the
|
|
135
|
+
* background, never blocks the caller.
|
|
136
|
+
*/
|
|
137
|
+
beginTurn(sessionId: string, triggerMessageId?: string): Promise<TurnHandle>;
|
|
138
|
+
/**
|
|
139
|
+
* Declare the turn finished. A stale handle (a newer turn — or a close —
|
|
140
|
+
* has bumped this session's generation) is ignored: finish(turn N) can
|
|
141
|
+
* never override begin(turn N+1). Reconciliation runs detached.
|
|
142
|
+
*/
|
|
143
|
+
finishTurn(handle: TurnHandle): void;
|
|
144
|
+
/**
|
|
145
|
+
* Terminal transition (fork teardown). Serialized behind any in-flight
|
|
146
|
+
* write — a `closed` can never race the turn's idle — and reclaimed once
|
|
147
|
+
* settled. Resolves after one bounded settle with a STRUCTURED outcome:
|
|
148
|
+
* `closed` / `stale` / `permanent_failure` are terminal; `retrying` means
|
|
149
|
+
* background reconciliation continues — the caller keeps ownership of the
|
|
150
|
+
* session until `terminal` resolves. A close is never silently "done":
|
|
151
|
+
* every fate is observable.
|
|
152
|
+
*/
|
|
153
|
+
closeSession(sessionId: string): Promise<SessionCloseResult>;
|
|
154
|
+
/**
|
|
155
|
+
* Session is dead (stale / superseded) — no further lifecycle writes, and
|
|
156
|
+
* the entry is reclaimed (immediately when idle; at the end of an in-flight
|
|
157
|
+
* write otherwise, unless a new turn revives it in the meantime).
|
|
158
|
+
*/
|
|
159
|
+
dropSession(sessionId: string): void;
|
|
160
|
+
/** Every tracked session is dead (server closed them all — new_session). */
|
|
161
|
+
dropAllSessions(): void;
|
|
162
|
+
/**
|
|
163
|
+
* One best-effort reconcile pass over unsettled sessions within a hard
|
|
164
|
+
* deadline (shutdown). Returns the number still unsettled.
|
|
165
|
+
*/
|
|
166
|
+
flush(deadlineMs: number): Promise<number>;
|
|
167
|
+
dispose(): void;
|
|
168
|
+
/**
|
|
169
|
+
* Get-or-create the entry and take the next generation. A dropped entry is
|
|
170
|
+
* REUSED (not replaced): its `writing` flag keeps the single-writer chain
|
|
171
|
+
* intact if a pre-drop write is still on the wire, and the generation stays
|
|
172
|
+
* monotonic across the drop boundary.
|
|
173
|
+
*/
|
|
174
|
+
private upsert;
|
|
175
|
+
private waitFor;
|
|
176
|
+
private isReconciled;
|
|
177
|
+
private isAbandoned;
|
|
178
|
+
/** Nothing more to do for the current desired state (written or given up). */
|
|
179
|
+
private isSettled;
|
|
180
|
+
private pump;
|
|
181
|
+
private writeLoop;
|
|
182
|
+
private classify;
|
|
183
|
+
/**
|
|
184
|
+
* Drop the entry when it can never write again: dropped (and no write on
|
|
185
|
+
* the wire), a terminal `closed` that landed, or a `closed` that failed
|
|
186
|
+
* permanently (its fate has been reported via closeSession's outcome — an
|
|
187
|
+
* entry kept around would be an unowned leak, not a recovery path). Called
|
|
188
|
+
* after every write settles and from dropSession — this is what keeps the
|
|
189
|
+
* Map bounded on a long-lived daemon churning fork sessions.
|
|
190
|
+
*/
|
|
191
|
+
private reclaim;
|
|
192
|
+
private scheduleRetry;
|
|
193
|
+
private cancelRetry;
|
|
194
|
+
private resolveWaiters;
|
|
195
|
+
/** Resolve closeSession terminal waiters covered by this settle, once. */
|
|
196
|
+
private settleCloseTerminal;
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=session-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-lifecycle.d.ts","sourceRoot":"","sources":["../src/session-lifecycle.ts"],"names":[],"mappings":"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"}
|