deepline 0.3.128 → 0.3.129
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/bundling-sources/sdk/src/client.ts +34 -9
- package/dist/bundling-sources/sdk/src/http.ts +22 -0
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +22 -0
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +265 -2
- package/dist/bundling-sources/shared_libs/play-runtime/bounded-batch-function.ts +682 -0
- package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +21 -5
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +5390 -1732
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +107 -1
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/commands/roll-execution-relay.ts +7 -0
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +229 -7
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-registry.ts +25 -4
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-capacity.ts +71 -0
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-drain.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-topology.ts +4 -1
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +694 -28
- package/dist/bundling-sources/shared_libs/play-runtime/egress-bandwidth-probe.ts +167 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execute-server-timing.ts +103 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-receipt-output-reference.ts +34 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-response-size.ts +27 -0
- package/dist/bundling-sources/shared_libs/play-runtime/gateway-postgres-admission.ts +66 -1
- package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +425 -71
- package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +210 -32
- package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +27 -13
- package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +19 -6
- package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +61 -2
- package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/contracts.ts +33 -1
- package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/job.ts +42 -1
- package/dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts +11 -11
- package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +49 -16
- package/dist/bundling-sources/shared_libs/play-runtime/map-memory-limits.ts +1653 -98
- package/dist/bundling-sources/shared_libs/play-runtime/memory-ledger.ts +807 -0
- package/dist/bundling-sources/shared_libs/play-runtime/memory-pressure-signal.ts +138 -0
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +85 -3
- package/dist/bundling-sources/shared_libs/play-runtime/persistence-latch.ts +60 -2
- package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +46 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/contracts.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/job.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/ports.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/postgres-adapter.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +70 -27
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +56 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/adaptive-provider-capacity-controller.ts +192 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/epoch-aimd-rate-controller.ts +194 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/fixture-capacity-simulator.ts +220 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/gradient2-concurrency-controller.ts +214 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-capacity-policy.ts +43 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-concurrency-policy.ts +30 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-rate-policy.ts +95 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-throttle-classifier.ts +40 -0
- package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +1535 -11
- package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +49 -2
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +6 -1
- package/dist/bundling-sources/shared_libs/play-runtime/run-log-buffer.ts +55 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/egress-probe.ts +221 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +339 -29
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-deadline.ts +28 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +192 -165
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +90 -5
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +281 -6
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +27 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/local-process.ts +19 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +108 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +40 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +11 -5
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +30 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api-compression.ts +276 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +723 -115
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +98 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +3 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-environment.ts +41 -4
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-flow.ts +448 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-map-row-feed.ts +215 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +11 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +161 -14
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-value.ts +184 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-writer.ts +607 -121
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sandbox-placement-policy.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-writer.ts +21 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +15 -2
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +71 -14
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-deploy-task.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +288 -119
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +8 -6
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +28 -3
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/canonical-integration-operation-store.ts +179 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-heavy-request-admission.ts +80 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-progress-registry.ts +31 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-store-contract.ts +104 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-reference.ts +47 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-retirement.ts +193 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-storage.ts +420 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +41 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +134 -3
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +1657 -95
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +885 -73
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-completion-coalescer.ts +452 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +601 -42
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-terminal-transition.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-value-storage.ts +371 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-resource-metrics.ts +86 -7
- package/dist/bundling-sources/shared_libs/play-runtime/secret-redaction.ts +153 -22
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/index.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/receipt-cohort.ts +188 -38
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/runtime-step-receipts-adapter.ts +28 -13
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +44 -1
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +56 -4
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +2 -0
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +16 -10
- package/dist/bundling-sources/shared_libs/plays/dataset.ts +4 -1
- package/dist/cli/index.js +250 -38
- package/dist/cli/index.mjs +250 -38
- package/dist/{compiler-manifest-DfSnbCTW.d.mts → compiler-manifest-BIqRyj5m.d.mts} +1 -1
- package/dist/{compiler-manifest-DfSnbCTW.d.ts → compiler-manifest-BIqRyj5m.d.ts} +1 -1
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +231 -35
- package/dist/index.mjs +231 -35
- package/dist/install-integrity.json +31 -2
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/dist/plays/bundle-play-file.mjs +65 -1
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +1 -1
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
|
@@ -1,27 +1,346 @@
|
|
|
1
|
+
import type { RuntimeMapHeapAdmissionSnapshot } from './map-memory-limits';
|
|
2
|
+
import type {
|
|
3
|
+
RuntimeMemoryLedger,
|
|
4
|
+
RuntimeMemoryLedgerSnapshot,
|
|
5
|
+
} from './memory-ledger';
|
|
1
6
|
import type {
|
|
2
7
|
PlayExecutionGovernor,
|
|
8
|
+
ProviderPermit,
|
|
3
9
|
WorkLease,
|
|
4
10
|
} from './governor/governor';
|
|
11
|
+
import type {
|
|
12
|
+
ProviderConcurrencyGrant,
|
|
13
|
+
ProviderPacingGrant,
|
|
14
|
+
} from './governor/rate-state-backend';
|
|
15
|
+
import type { ExecuteServerTiming } from './execute-server-timing';
|
|
5
16
|
|
|
6
17
|
export type RuntimeResourceLease = WorkLease;
|
|
18
|
+
export type RuntimeProviderPermit = ProviderPermit;
|
|
7
19
|
|
|
8
20
|
export type RuntimeResourceObservation = {
|
|
9
21
|
toolId?: string | null;
|
|
10
22
|
providerResourceKey?: string | null;
|
|
23
|
+
/**
|
|
24
|
+
* Canonical pacing-provider bucket for fixture/report attribution. This is
|
|
25
|
+
* intentionally separate from `providerResourceKey`: the latter retains
|
|
26
|
+
* the tool-keyed physical-request facts that provenance-disabled fixtures
|
|
27
|
+
* need, while this joins admission and response residence under the bucket
|
|
28
|
+
* the shared controller actually permitted.
|
|
29
|
+
*/
|
|
30
|
+
providerTelemetryKey?: string | null;
|
|
31
|
+
/**
|
|
32
|
+
* Read-only shared-controller state captured with the permit that admitted
|
|
33
|
+
* this physical request. Observation never adjusts rate or concurrency.
|
|
34
|
+
*/
|
|
35
|
+
providerConcurrencyGrant?: ProviderConcurrencyGrant | null;
|
|
36
|
+
/** Effective shared-rate reading for every provider permit. */
|
|
37
|
+
providerPacingGrant?: ProviderPacingGrant | null;
|
|
38
|
+
/**
|
|
39
|
+
* Physical provider work already resident in this runtime when this request
|
|
40
|
+
* crossed the dispatch boundary. This is a bounded, run-local diagnostic;
|
|
41
|
+
* it never participates in provider admission or controller decisions.
|
|
42
|
+
*/
|
|
43
|
+
providerRunInFlightAtDispatch?: number | null;
|
|
11
44
|
rowEstimatedBytes?: number | null;
|
|
12
45
|
rowAdmissionWaitMs?: number | null;
|
|
13
46
|
toolAdmissionWaitMs?: number | null;
|
|
47
|
+
providerAdmissionWaitMs?: number | null;
|
|
48
|
+
externalExecutionWaitMs?: number | null;
|
|
14
49
|
providerLatencyMs?: number | null;
|
|
50
|
+
/** Wait for the runner-to-app transport slot inside provider residence. */
|
|
51
|
+
transportSlotWaitMs?: number | null;
|
|
52
|
+
/** Fetch dispatch to response headers. */
|
|
53
|
+
fetchToHeadersMs?: number | null;
|
|
54
|
+
/** The execute route's own `Server-Timing` account of that same request. */
|
|
55
|
+
executeServerTiming?: ExecuteServerTiming | null;
|
|
56
|
+
/** Response headers to a fully read and parsed body. */
|
|
57
|
+
bodyReadMs?: number | null;
|
|
58
|
+
/** Sandbox-side simulated provider residence in fixture mode. */
|
|
59
|
+
fixtureDelayMs?: number | null;
|
|
15
60
|
providerSuccess?: boolean;
|
|
16
61
|
provider429?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* A Deepline relay/gateway concurrency shed (429 with the concurrency
|
|
64
|
+
* backpressure marker). Counted apart from provider 429s and never fed to
|
|
65
|
+
* provider pacing: the shed is our own admission, not the provider's.
|
|
66
|
+
*/
|
|
67
|
+
concurrencyShedDelayMs?: number | null;
|
|
17
68
|
retryAfterMs?: number | null;
|
|
18
69
|
receiptLatencyMs?: number | null;
|
|
70
|
+
/** Per-dispatch-group receipt get+claim round trips in the hydration turn. */
|
|
71
|
+
receiptClaimMs?: number | null;
|
|
72
|
+
/**
|
|
73
|
+
* What a hydration turn queued for a slot on the bounded completed-receipt
|
|
74
|
+
* hydration lane, before the claim round trip inside the turn started
|
|
75
|
+
* counting. Observed once per call the turn is blocking, and an explicit
|
|
76
|
+
* zero for a turn that found the lane free, so the population is every call
|
|
77
|
+
* that took a turn rather than only the ones that queued.
|
|
78
|
+
*/
|
|
79
|
+
receiptHydrationGateWaitMs?: number | null;
|
|
80
|
+
/**
|
|
81
|
+
* Time a provider response body waited for byte headroom before it was read.
|
|
82
|
+
* Headers have already arrived, so this is not provider residence.
|
|
83
|
+
*/
|
|
84
|
+
providerBodyAdmissionWaitMs?: number | null;
|
|
85
|
+
/**
|
|
86
|
+
* A queued tool call's enqueue to the launch of the dispatch group that
|
|
87
|
+
* carries it: coalescing window, group and lane caps, and dispatcher passes.
|
|
88
|
+
*/
|
|
89
|
+
dispatchQueueWaitMs?: number | null;
|
|
90
|
+
/**
|
|
91
|
+
* Wall inside one map row between a tool call's result reaching the resolver
|
|
92
|
+
* and that resolver's next enqueue — or the resolver returning. This is the
|
|
93
|
+
* row's own time: user code, cell serialization, checkpoint work.
|
|
94
|
+
*/
|
|
95
|
+
rowResolverGapMs?: number | null;
|
|
96
|
+
/** One logical tool call's enqueue to its result delivery. */
|
|
97
|
+
toolCallLogicalWallMs?: number | null;
|
|
98
|
+
/**
|
|
99
|
+
* One provider call's fully read and parsed response body to the moment that
|
|
100
|
+
* call's result is handed back to the row that asked for it: receipt
|
|
101
|
+
* completion, result wrapping, and whatever the dispatcher does in between.
|
|
102
|
+
* Recorded only for a call that made a provider request — a cache hit and a
|
|
103
|
+
* follower deliver a body they never read.
|
|
104
|
+
*/
|
|
105
|
+
resultDeliveryMs?: number | null;
|
|
106
|
+
/**
|
|
107
|
+
* Sub-phases of `resultDelivery`, in the order one call walks them. With
|
|
108
|
+
* `receiptCompletionQueue` and `receiptCompletionFlight` between them they
|
|
109
|
+
* partition the delivery interval, so a delivery nobody can explain is a
|
|
110
|
+
* named gap between two of these rather than an unmeasured whole.
|
|
111
|
+
*
|
|
112
|
+
* All five are observed ONCE PER CALL, for exactly the calls `resultDelivery`
|
|
113
|
+
* is observed for. A stage a given path does not have is recorded as an
|
|
114
|
+
* explicit `0` at the point where it would otherwise close — an always-fresh
|
|
115
|
+
* call has no receipt to publish, so its publication stages are zero rather
|
|
116
|
+
* than absent. A zero therefore means "this stage is not on this path", and a
|
|
117
|
+
* missing observation would mean the per-call means were taken over different
|
|
118
|
+
* populations and could not be summed against the whole.
|
|
119
|
+
*
|
|
120
|
+
* `deliveryWrap`: parsed provider body to the wrapped result existing —
|
|
121
|
+
* result metadata lookup, dataset attach, and the rest of what the module
|
|
122
|
+
* dispatcher does before it hands the result to its Tool Call job.
|
|
123
|
+
*/
|
|
124
|
+
deliveryWrapMs?: number | null;
|
|
125
|
+
/**
|
|
126
|
+
* Wrapped result to this call's completion reaching the completion writer:
|
|
127
|
+
* the Tool Call job's return path, and then either the cohort's one-turn
|
|
128
|
+
* publication coalescing or — off the cohort, for a fenced, uncacheable, or
|
|
129
|
+
* natively batched call — the resolve site's own re-wrap and completion
|
|
130
|
+
* serialization. Every receipt-backed path measures it; only a call with no
|
|
131
|
+
* receipt at all records the explicit zero.
|
|
132
|
+
*/
|
|
133
|
+
deliveryPublishWaitMs?: number | null;
|
|
134
|
+
/**
|
|
135
|
+
* This call's own receipt write settling to the row's pending tool call
|
|
136
|
+
* resolving: cohort group resolution or per-member presentation, and the
|
|
137
|
+
* resolver hand-back. Taken from the per-receipt settlement, never from the
|
|
138
|
+
* batch that carried it — a row waits for its own receipt to be durable.
|
|
139
|
+
*/
|
|
140
|
+
deliveryResolveMs?: number | null;
|
|
141
|
+
/**
|
|
142
|
+
* Sub-phases of `receiptCompletionFlight`, which is otherwise one opaque
|
|
143
|
+
* batch launch to response. `flightSerialize` is the batch's pre-transport
|
|
144
|
+
* work — the queue and egress accounting, completion validation, and wire
|
|
145
|
+
* record construction; `flightTransport` is the completion request itself,
|
|
146
|
+
* request body through parsed response, measured on completion requests only
|
|
147
|
+
* rather than borrowed from `gatewayRoundTrip`, which every runtime API
|
|
148
|
+
* action shares; and `flightDecode` is everything after it, including a
|
|
149
|
+
* `reconcileIncomplete` durable read-back.
|
|
150
|
+
*
|
|
151
|
+
* Like `receiptCompletionFlight` itself, each is recorded once per RECEIPT in
|
|
152
|
+
* the batch rather than once per coalesced statement: every receipt inherits
|
|
153
|
+
* the flight of the batch that carried it, so these stay per-call phases
|
|
154
|
+
* comparable with the rest of the delivery partition.
|
|
155
|
+
*/
|
|
156
|
+
flightSerializeMs?: number | null;
|
|
157
|
+
flightTransportMs?: number | null;
|
|
158
|
+
flightDecodeMs?: number | null;
|
|
159
|
+
/** Receipt gateway `Server-Timing` entries for one runtime API response. */
|
|
160
|
+
gatewayAuthLaunchMs?: number | null;
|
|
161
|
+
gatewayAuthVerifyMs?: number | null;
|
|
162
|
+
gatewayBodyParseMs?: number | null;
|
|
163
|
+
/** Gunzip of a compressed request body, inside `gatewayBodyParseMs`. */
|
|
164
|
+
gatewayBodyInflateMs?: number | null;
|
|
165
|
+
gatewayPoolWaitMs?: number | null;
|
|
166
|
+
/** Inside gatewayCallback: bounded R2 receipt-value persistence wall. */
|
|
167
|
+
gatewayReceiptValuePersistMs?: number | null;
|
|
168
|
+
gatewayCallbackMs?: number | null;
|
|
169
|
+
/** Client-measured wall of that same request, for the client/server split. */
|
|
170
|
+
gatewayRoundTripMs?: number | null;
|
|
171
|
+
/** Runner CPU-path wall before the request starts: JSON serialization once. */
|
|
172
|
+
gatewayRequestSerializeMs?: number | null;
|
|
173
|
+
/** Runner CPU-path wall before the request starts: request wire packing. */
|
|
174
|
+
gatewayRequestPackMs?: number | null;
|
|
175
|
+
/** The gateway's own account of its auth-session cache for that request. */
|
|
176
|
+
gatewayAuthSession?: 'hit' | 'miss' | 'coalesced' | 'unknown' | null;
|
|
177
|
+
/**
|
|
178
|
+
* Request body bytes for one runtime API request: what was serialized, and
|
|
179
|
+
* what actually went on the wire. Recorded for EVERY request, compressed or
|
|
180
|
+
* not, so the run-level ratio is taken over the whole population rather than
|
|
181
|
+
* the flattering subset. On a sandbox ~95 ms from the gateway it is the WIRE
|
|
182
|
+
* size, not the decoded size, that sets how many congestion-window round
|
|
183
|
+
* trips a request costs.
|
|
184
|
+
*/
|
|
185
|
+
gatewayRequestRawBytes?: number | null;
|
|
186
|
+
gatewayRequestWireBytes?: number | null;
|
|
187
|
+
/** Completion enqueue to the launch of the batch that carries it. */
|
|
188
|
+
receiptCompletionQueueMs?: number | null;
|
|
189
|
+
/**
|
|
190
|
+
* Completion batch launch to its gateway response, recorded once per RECEIPT
|
|
191
|
+
* in that batch. Once per statement made it a mean over a different
|
|
192
|
+
* population than the per-call phases it partitions with, which on a 1000-row
|
|
193
|
+
* modal shape left most of `resultDelivery` owned by nothing.
|
|
194
|
+
*/
|
|
195
|
+
receiptCompletionFlightMs?: number | null;
|
|
196
|
+
/**
|
|
197
|
+
* Completion responses that returned no stored receipt and had to be
|
|
198
|
+
* hydrated by a durable-store read-back.
|
|
199
|
+
*/
|
|
200
|
+
receiptCompletionReadBacks?: number | null;
|
|
201
|
+
/** Wall for one batched durable receipt read-back after a compact ack. */
|
|
202
|
+
receiptCompletionReadBackMs?: number | null;
|
|
203
|
+
/** Compact `persisted` acknowledgements that reused the caller's live value. */
|
|
204
|
+
receiptCompletionLiveResultReuses?: number | null;
|
|
205
|
+
/** Cache-cohort completions that retained their already-live result. */
|
|
206
|
+
receiptCompletionLivePublicationResults?: number | null;
|
|
207
|
+
/** Compact `existing` acknowledgements naming an already-durable winner. */
|
|
208
|
+
receiptCompletionExistingWinners?: number | null;
|
|
209
|
+
/** Compact terminal acknowledgements from a gateway without a disposition. */
|
|
210
|
+
receiptCompletionLegacyAcknowledgements?: number | null;
|
|
211
|
+
/** Missing or malformed completion acknowledgement entries. */
|
|
212
|
+
receiptCompletionMissingAcknowledgements?: number | null;
|
|
213
|
+
/** A completion acknowledgement that was not terminal. */
|
|
214
|
+
receiptCompletionNonterminalAcknowledgements?: number | null;
|
|
215
|
+
/** Read-back entries that recovered a complete durable output. */
|
|
216
|
+
receiptCompletionReadBackRecovered?: number | null;
|
|
217
|
+
/** Read-back entries that still did not yield a complete durable output. */
|
|
218
|
+
receiptCompletionReadBackMissing?: number | null;
|
|
219
|
+
receiptEgressBatchSize?: number | null;
|
|
220
|
+
receiptEgressBytes?: number | null;
|
|
221
|
+
/** Bounded completion-writer state sampled at each state transition. */
|
|
222
|
+
receiptCompletionWriterInFlightBatches?: number | null;
|
|
223
|
+
receiptCompletionWriterQueued?: number | null;
|
|
224
|
+
receiptCompletionWriterBufferedItems?: number | null;
|
|
225
|
+
receiptCompletionWriterBufferedBytes?: number | null;
|
|
19
226
|
sheetFlushLatencyMs?: number | null;
|
|
20
227
|
sheetFlushBytes?: number | null;
|
|
21
|
-
memoryBytes?: number | null;
|
|
22
228
|
};
|
|
23
229
|
|
|
24
230
|
export type RuntimeResourceSnapshot = {
|
|
231
|
+
/**
|
|
232
|
+
* Selected execute-route stages across every physical request that published
|
|
233
|
+
* the complete timing header. Kept once per run so mixed-provider fixtures
|
|
234
|
+
* cannot overflow the terminal metadata envelope.
|
|
235
|
+
*/
|
|
236
|
+
executeRoute?: RuntimeExecuteRouteTiming;
|
|
237
|
+
phases: {
|
|
238
|
+
rowAdmission: RuntimePhaseDistribution;
|
|
239
|
+
providerAdmission: RuntimePhaseDistribution;
|
|
240
|
+
externalExecution: RuntimePhaseDistribution;
|
|
241
|
+
providerResidence: RuntimePhaseDistribution;
|
|
242
|
+
/**
|
|
243
|
+
* Sub-phases of providerResidence, so a slow call can be attributed:
|
|
244
|
+
* residence = fixtureDelay + transportSlotWait + fetchToHeaders + bodyRead
|
|
245
|
+
* + an unattributed remainder.
|
|
246
|
+
*/
|
|
247
|
+
fixtureDelay: RuntimePhaseDistribution;
|
|
248
|
+
transportSlotWait: RuntimePhaseDistribution;
|
|
249
|
+
fetchToHeaders: RuntimePhaseDistribution;
|
|
250
|
+
bodyRead: RuntimePhaseDistribution;
|
|
251
|
+
/** Sampled setTimeout lateness, not a per-call phase. */
|
|
252
|
+
eventLoopLag: RuntimePhaseDistribution;
|
|
253
|
+
receiptSettlement: RuntimePhaseDistribution;
|
|
254
|
+
/**
|
|
255
|
+
* Sub-phases of receipt orchestration, which `receiptSettlement` alone
|
|
256
|
+
* cannot separate: the claim turn before provider work, the completion's
|
|
257
|
+
* wait for a batch, and that batch's own flight.
|
|
258
|
+
*/
|
|
259
|
+
receiptClaim: RuntimePhaseDistribution;
|
|
260
|
+
/**
|
|
261
|
+
* The queue in front of `receiptClaim`. A bounded lane serializes
|
|
262
|
+
* completed-receipt payload expansion, so a shape whose receipts are large
|
|
263
|
+
* keeps the lane busy and its dispatch groups wait for a slot before their
|
|
264
|
+
* claim can start. That wall sits inside `toolCallLogicalWall` after
|
|
265
|
+
* `dispatchQueueWait` and before any provider work, and no other phase
|
|
266
|
+
* covers it, so a logical wall that residence and delivery cannot explain
|
|
267
|
+
* is read against this phase first.
|
|
268
|
+
*
|
|
269
|
+
* Charged to each call in the group whose turn it is — like
|
|
270
|
+
* `receiptCompletionFlight`, and unlike `receiptClaim`, which is recorded
|
|
271
|
+
* once per turn — so its per-call mean is over the same population as the
|
|
272
|
+
* wall it is subtracted from. The per-map `receipt_hydration_gate` log
|
|
273
|
+
* line still reports the turn-level view (turns, queued turns, and the
|
|
274
|
+
* lane's own total wait).
|
|
275
|
+
*/
|
|
276
|
+
receiptHydrationGateWait: RuntimePhaseDistribution;
|
|
277
|
+
receiptCompletionQueue: RuntimePhaseDistribution;
|
|
278
|
+
receiptCompletionFlight: RuntimePhaseDistribution;
|
|
279
|
+
/** One durable read-back batch after a compact completion acknowledgement. */
|
|
280
|
+
receiptCompletionReadBack: RuntimePhaseDistribution;
|
|
281
|
+
rowPersistence: RuntimePhaseDistribution;
|
|
282
|
+
/**
|
|
283
|
+
* The three phases that account for a row's life OUTSIDE the per-call
|
|
284
|
+
* phases above. A modal shape whose measured per-call phases sum to a
|
|
285
|
+
* quarter of the wall a row spends per call is spending the rest either
|
|
286
|
+
* queued for a dispatch group (`dispatchQueueWait`) or inside its own
|
|
287
|
+
* resolver between calls (`rowResolverGap`); `toolCallLogicalWall` is the
|
|
288
|
+
* enqueue-to-delivery total those two must be checked against.
|
|
289
|
+
*/
|
|
290
|
+
dispatchQueueWait: RuntimePhaseDistribution;
|
|
291
|
+
rowResolverGap: RuntimePhaseDistribution;
|
|
292
|
+
toolCallLogicalWall: RuntimePhaseDistribution;
|
|
293
|
+
/**
|
|
294
|
+
* The tail of `toolCallLogicalWall`: parsed provider body to the row's own
|
|
295
|
+
* result. `providerResidence` ends where this begins, so a logical wall
|
|
296
|
+
* that neither residence nor `dispatchQueueWait` explains is being spent
|
|
297
|
+
* here — receipt completion and delivery — rather than on the provider.
|
|
298
|
+
*/
|
|
299
|
+
resultDelivery: RuntimePhaseDistribution;
|
|
300
|
+
/**
|
|
301
|
+
* The partition of `resultDelivery`, in call order:
|
|
302
|
+
* `deliveryWrap` + `deliveryPublishWait` + `receiptCompletionQueue` +
|
|
303
|
+
* `receiptCompletionFlight` + `deliveryResolve` = `resultDelivery`, and
|
|
304
|
+
* `flightSerialize` + `flightTransport` + `flightDecode` =
|
|
305
|
+
* `receiptCompletionFlight`. Every one of them is recorded for exactly the
|
|
306
|
+
* calls `resultDelivery` is — one that read a provider body of its own —
|
|
307
|
+
* counting the same population at the same per-call granularity: the
|
|
308
|
+
* publication phases are an explicit zero on a path without a receipt
|
|
309
|
+
* (always-fresh), they are measured at the resolve site on a receipt-backed
|
|
310
|
+
* path that does not reach the receipt cohort (fenced, uncacheable, or
|
|
311
|
+
* natively batched), and the flight and its three parts are recorded once
|
|
312
|
+
* per receipt rather than once per coalesced completion statement. The
|
|
313
|
+
* counts are therefore comparable on any shape, and a difference between
|
|
314
|
+
* the sum and the whole is a real gap rather than a sampling artifact.
|
|
315
|
+
*/
|
|
316
|
+
deliveryWrap: RuntimePhaseDistribution;
|
|
317
|
+
deliveryPublishWait: RuntimePhaseDistribution;
|
|
318
|
+
deliveryResolve: RuntimePhaseDistribution;
|
|
319
|
+
flightSerialize: RuntimePhaseDistribution;
|
|
320
|
+
flightTransport: RuntimePhaseDistribution;
|
|
321
|
+
flightDecode: RuntimePhaseDistribution;
|
|
322
|
+
/**
|
|
323
|
+
* The receipt gateway's own `Server-Timing` account of a runtime API
|
|
324
|
+
* request, beside the client-measured wall of the same request
|
|
325
|
+
* (`gatewayRoundTrip`). The gateway's action duration starts AFTER
|
|
326
|
+
* authentication, so its logs cannot see `gatewayAuthLaunch`,
|
|
327
|
+
* `gatewayAuthVerify`, or `gatewayBodyParse`; a round trip far above the
|
|
328
|
+
* server-reported sum is network, and one that matches it is the gateway.
|
|
329
|
+
*/
|
|
330
|
+
gatewayAuthLaunch: RuntimePhaseDistribution;
|
|
331
|
+
gatewayAuthVerify: RuntimePhaseDistribution;
|
|
332
|
+
gatewayBodyParse: RuntimePhaseDistribution;
|
|
333
|
+
/** Inside `gatewayBodyParse`, not beside it. Zero on uncompressed requests. */
|
|
334
|
+
gatewayBodyInflate: RuntimePhaseDistribution;
|
|
335
|
+
gatewayPoolWait: RuntimePhaseDistribution;
|
|
336
|
+
/** Inside `gatewayCallback`, never add it beside that total. */
|
|
337
|
+
gatewayReceiptValuePersist: RuntimePhaseDistribution;
|
|
338
|
+
gatewayCallback: RuntimePhaseDistribution;
|
|
339
|
+
gatewayRoundTrip: RuntimePhaseDistribution;
|
|
340
|
+
/** Runner-local work deliberately excluded from `gatewayRoundTrip`. */
|
|
341
|
+
gatewayRequestSerialize: RuntimePhaseDistribution;
|
|
342
|
+
gatewayRequestPack: RuntimePhaseDistribution;
|
|
343
|
+
};
|
|
25
344
|
rows: {
|
|
26
345
|
acquired: number;
|
|
27
346
|
estimatedBytes: number;
|
|
@@ -36,16 +355,334 @@ export type RuntimeResourceSnapshot = {
|
|
|
36
355
|
bytes: number;
|
|
37
356
|
latencyMsEwma: number | null;
|
|
38
357
|
};
|
|
358
|
+
resultEgress: {
|
|
359
|
+
batches: number;
|
|
360
|
+
receipts: number;
|
|
361
|
+
bytes: number;
|
|
362
|
+
maxBatchBytes: number | null;
|
|
363
|
+
/** High-water marks of the bounded completion writer for this run. */
|
|
364
|
+
writerPeakInFlightBatches: number;
|
|
365
|
+
writerPeakQueued: number;
|
|
366
|
+
writerPeakBufferedItems: number;
|
|
367
|
+
writerPeakBufferedBytes: number;
|
|
368
|
+
/**
|
|
369
|
+
* Receipts whose completion response carried no stored receipt and were
|
|
370
|
+
* hydrated by a second full read of the durable store.
|
|
371
|
+
*/
|
|
372
|
+
readBacks: number;
|
|
373
|
+
/** Compact acknowledgements where this caller could reuse the live value. */
|
|
374
|
+
liveResultReuses: number;
|
|
375
|
+
/** Publish-only cache cohorts that retained their already-live value. */
|
|
376
|
+
livePublicationResults: number;
|
|
377
|
+
/** Compact acknowledgements naming an already-durable winner. */
|
|
378
|
+
existingWinners: number;
|
|
379
|
+
/** Compact acknowledgements from an older gateway without a disposition. */
|
|
380
|
+
legacyAcknowledgements: number;
|
|
381
|
+
/** Completion response entries that were absent or malformed. */
|
|
382
|
+
missingAcknowledgements: number;
|
|
383
|
+
/** Completion response entries that did not reach a terminal state. */
|
|
384
|
+
nonterminalAcknowledgements: number;
|
|
385
|
+
/** Read-back entries that did recover a complete durable output. */
|
|
386
|
+
readBackRecovered: number;
|
|
387
|
+
/** Read-back entries still missing a complete durable output. */
|
|
388
|
+
readBackMissing: number;
|
|
389
|
+
};
|
|
390
|
+
/** Relay concurrency sheds the runner paced on instead of failing rows. */
|
|
391
|
+
concurrencyShed: {
|
|
392
|
+
count: number;
|
|
393
|
+
delayMsEwma: number | null;
|
|
394
|
+
};
|
|
395
|
+
/**
|
|
396
|
+
* What the receipt gateway reported about itself, counted rather than timed.
|
|
397
|
+
* A miss rate near one means every runtime API request paid a fresh token
|
|
398
|
+
* verification, which the gateway's own action logs do not show.
|
|
399
|
+
*/
|
|
400
|
+
gateway: {
|
|
401
|
+
authSession: {
|
|
402
|
+
hit: number;
|
|
403
|
+
miss: number;
|
|
404
|
+
coalesced: number;
|
|
405
|
+
unknown: number;
|
|
406
|
+
};
|
|
407
|
+
/**
|
|
408
|
+
* What the runtime API transport put on the wire across the run.
|
|
409
|
+
*
|
|
410
|
+
* `wireBytes / rawBytes` is the realized compression ratio, over every
|
|
411
|
+
* request rather than only the compressed ones. `count` is the denominator
|
|
412
|
+
* for both, so a readout can also state mean request size — the number the
|
|
413
|
+
* ~95 ms round trip is multiplied by.
|
|
414
|
+
*/
|
|
415
|
+
requestBody: {
|
|
416
|
+
count: number;
|
|
417
|
+
rawBytes: number;
|
|
418
|
+
wireBytes: number;
|
|
419
|
+
};
|
|
420
|
+
};
|
|
39
421
|
providers: Record<
|
|
40
422
|
string,
|
|
41
423
|
{
|
|
424
|
+
admission: RuntimePhaseTiming;
|
|
425
|
+
residence: RuntimePhaseTiming;
|
|
426
|
+
fetchToHeaders: RuntimePhaseTiming;
|
|
427
|
+
latencyMsEwma: number | null;
|
|
428
|
+
retryAfterMsEwma: number | null;
|
|
429
|
+
provider429Count: number;
|
|
430
|
+
}
|
|
431
|
+
>;
|
|
432
|
+
/**
|
|
433
|
+
* Capped, canonical-provider attribution. Unlike `providers`, each entry
|
|
434
|
+
* joins permit wait and provider residence for one controller bucket, so a
|
|
435
|
+
* fixture readout can show where external response time went without
|
|
436
|
+
* conflating an admission key with a tool id.
|
|
437
|
+
*/
|
|
438
|
+
providerAttribution: Record<
|
|
439
|
+
string,
|
|
440
|
+
{
|
|
441
|
+
admission: RuntimePhaseTiming;
|
|
442
|
+
residence: RuntimePhaseTiming;
|
|
443
|
+
fixtureDelay: RuntimePhaseTiming;
|
|
444
|
+
transportSlotWait: RuntimePhaseTiming;
|
|
445
|
+
fetchToHeaders: RuntimePhaseTiming;
|
|
446
|
+
bodyRead: RuntimePhaseTiming;
|
|
447
|
+
/** Local response-body byte-admission total in milliseconds. */
|
|
448
|
+
gateMs: number;
|
|
449
|
+
controller: {
|
|
450
|
+
/** Physical requests whose permit carried shared-controller context. */
|
|
451
|
+
permits: number;
|
|
452
|
+
/** Bucket occupancy captured before the request joined it. */
|
|
453
|
+
inFlightAtPermit: RuntimeSampleTiming;
|
|
454
|
+
/**
|
|
455
|
+
* Run-local physical provider work already resident when dispatch
|
|
456
|
+
* began. Unlike `inFlightAtPermit`, this is available to pure-rate
|
|
457
|
+
* buckets that deliberately have no shared concurrency lease.
|
|
458
|
+
*/
|
|
459
|
+
runInFlightAtDispatch: RuntimeSampleTiming;
|
|
460
|
+
/** Null when the active rate backend did not publish a reading. */
|
|
461
|
+
targetRequestsPerSecondEwma: number | null;
|
|
462
|
+
minimumRttMsEwma: number | null;
|
|
463
|
+
};
|
|
42
464
|
latencyMsEwma: number | null;
|
|
43
465
|
retryAfterMsEwma: number | null;
|
|
44
466
|
provider429Count: number;
|
|
45
467
|
}
|
|
46
468
|
>;
|
|
469
|
+
/**
|
|
470
|
+
* Process-level cost at snapshot time. On a 1 vCPU sandbox, cpu user+system
|
|
471
|
+
* milliseconds divided by the map wall is the runtime's own CPU floor.
|
|
472
|
+
*/
|
|
473
|
+
process: {
|
|
474
|
+
cpuUserMs: number;
|
|
475
|
+
cpuSystemMs: number;
|
|
476
|
+
rssBytes: number | null;
|
|
477
|
+
maxRssBytes: number | null;
|
|
478
|
+
heapUsedBytes: number | null;
|
|
479
|
+
externalBytes: number | null;
|
|
480
|
+
} | null;
|
|
481
|
+
/** Final heap-admission state of each map, keyed by table namespace. */
|
|
482
|
+
mapAdmission: Record<string, RuntimeMapHeapAdmissionSnapshot>;
|
|
483
|
+
/**
|
|
484
|
+
* The runtime's byte ledger: what it says it is holding, how that compares
|
|
485
|
+
* to what the process reports, and how often admission had to hold. Null
|
|
486
|
+
* when no ledger is attached to this governor.
|
|
487
|
+
*/
|
|
488
|
+
memory: RuntimeMemorySnapshot | null;
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* The ledger plus the admission counters that say how often bytes actually
|
|
493
|
+
* constrained the map. `predictedLiveBytes` diverging from `observedLiveBytes`
|
|
494
|
+
* by more than the calibration factor explains is the signal that the runtime
|
|
495
|
+
* is retaining bytes nothing registered.
|
|
496
|
+
*/
|
|
497
|
+
export type RuntimeMemorySnapshot = RuntimeMemoryLedgerSnapshot & {
|
|
498
|
+
/** Probes, across every map, that paused new row admission under pressure. */
|
|
499
|
+
admissionHolds: number;
|
|
500
|
+
/** Watchdog memory-pressure signals delivered to admission. */
|
|
501
|
+
externalPressureSignals: number;
|
|
502
|
+
/** Live-memory or RSS pressure episodes admission observed. */
|
|
503
|
+
memoryPressureEvents: number;
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
/** Aggregate phase timing from the runner's monotonic clock. */
|
|
507
|
+
export type RuntimePhaseTiming = {
|
|
508
|
+
count: number;
|
|
509
|
+
totalMs: number;
|
|
510
|
+
maxMs: number | null;
|
|
511
|
+
ewmaMs: number | null;
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Selected execute-route stages for the same population as `fetchToHeaders`.
|
|
516
|
+
* These are nested because they partition handler work inside that wall; they
|
|
517
|
+
* must never be added to provider residence as independent phases.
|
|
518
|
+
*/
|
|
519
|
+
export type RuntimeExecuteRouteTiming = {
|
|
520
|
+
/** Every selected stage was present for this many physical requests. */
|
|
521
|
+
count: number;
|
|
522
|
+
totalMs: number;
|
|
523
|
+
chargeOpenMs: number;
|
|
524
|
+
fixtureLoadMs: number;
|
|
525
|
+
executeMs: number;
|
|
526
|
+
/**
|
|
527
|
+
* Where `chargeOpenMs` went, nested rather than summed: these are disjoint
|
|
528
|
+
* slices of it, never independent phases. Present only when the deployed app
|
|
529
|
+
* publishes the complete substage set, so a rolling deploy cannot build this
|
|
530
|
+
* sum over a different request population than `chargeOpenMs` itself.
|
|
531
|
+
*/
|
|
532
|
+
chargeOpen?: {
|
|
533
|
+
count: number;
|
|
534
|
+
eligibilityMs: number;
|
|
535
|
+
capPreflightMs: number;
|
|
536
|
+
openMutationMs: number;
|
|
537
|
+
/** Wall slept in admission retry backoff: same-org OCC contention. */
|
|
538
|
+
retryWaitMs: number;
|
|
539
|
+
};
|
|
540
|
+
/**
|
|
541
|
+
* The execution gateway's own response-path timing, nested beside the app
|
|
542
|
+
* handler rather than summed into it. `upstreamHeadersMs` contains the
|
|
543
|
+
* handler `total`, which exposes the bounded relay-to-app platform/transit
|
|
544
|
+
* residual without claiming it is all network time.
|
|
545
|
+
*/
|
|
546
|
+
gateway?: {
|
|
547
|
+
count: number;
|
|
548
|
+
authLaunchMs: number;
|
|
549
|
+
authVerifyMs: number;
|
|
550
|
+
bodyParseMs: number;
|
|
551
|
+
dispatchPoolMs: number;
|
|
552
|
+
dispatchCallbackMs: number;
|
|
553
|
+
/** Relay fetch issuance -> app response headers; contains handler total. */
|
|
554
|
+
upstreamHeadersMs: number;
|
|
555
|
+
/** App headers -> relay's fully buffered upstream body. */
|
|
556
|
+
upstreamBodyMs: number;
|
|
557
|
+
};
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* A compact, unitless sample aggregate. Provider permits use it for bucket
|
|
562
|
+
* occupancy at admission, rather than mislabelling an in-flight count as ms.
|
|
563
|
+
*/
|
|
564
|
+
export type RuntimeSampleTiming = {
|
|
565
|
+
count: number;
|
|
566
|
+
total: number;
|
|
567
|
+
max: number | null;
|
|
568
|
+
ewma: number | null;
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* A fixture can touch many tool ids, but it should never make terminal
|
|
573
|
+
* diagnostics grow with unbounded provider cardinality. Keep the canonical
|
|
574
|
+
* attribution view useful for a multi-provider Play while rolling additional
|
|
575
|
+
* named buckets into a named remainder.
|
|
576
|
+
*/
|
|
577
|
+
// This record travels inside the fixed 32 KiB terminal metadata envelope.
|
|
578
|
+
// Eleven named controller buckets plus `other` exactly fill the twelve rows
|
|
579
|
+
// the fixture readout renders; the remainder preserves all physical work
|
|
580
|
+
// without allowing a mixed-provider run to drop every runtime diagnostic.
|
|
581
|
+
const MAX_PROVIDER_ATTRIBUTION_BUCKETS = 11;
|
|
582
|
+
const PROVIDER_ATTRIBUTION_OTHER_KEY = 'other';
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* One non-zero histogram bucket, as `[bucketIndex, count]`.
|
|
586
|
+
*
|
|
587
|
+
* Only non-zero buckets are emitted. A dense 18-entry array per phase would
|
|
588
|
+
* cost the terminal metadata record several kilobytes it does not have; a
|
|
589
|
+
* phase's durations in practice occupy a handful of adjacent buckets.
|
|
590
|
+
*/
|
|
591
|
+
export type RuntimePhaseHistogramBucket = [bucketIndex: number, count: number];
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* A phase timing plus the shape of its durations.
|
|
595
|
+
*
|
|
596
|
+
* A mean is dragged by the tail: one 13 s stall inside a thousand 150 ms calls
|
|
597
|
+
* moves it as far as adding 13 ms to every call, and those two facts call for
|
|
598
|
+
* opposite fixes. The percentiles separate them. They are bucket-resolution
|
|
599
|
+
* estimates — the bucket that holds the rank, interpolated linearly across
|
|
600
|
+
* that bucket's width — so they place a value inside a power-of-two band and
|
|
601
|
+
* never claim millisecond accuracy. No estimate exceeds the observed `maxMs`.
|
|
602
|
+
*/
|
|
603
|
+
export type RuntimePhaseDistribution = RuntimePhaseTiming & {
|
|
604
|
+
p50Ms: number | null;
|
|
605
|
+
p90Ms: number | null;
|
|
606
|
+
p99Ms: number | null;
|
|
607
|
+
/** Non-zero log2 buckets, ascending, as `[bucketIndex, count]` pairs. */
|
|
608
|
+
buckets: RuntimePhaseHistogramBucket[];
|
|
47
609
|
};
|
|
48
610
|
|
|
611
|
+
/**
|
|
612
|
+
* The fixed log2 duration histogram every phase records into.
|
|
613
|
+
*
|
|
614
|
+
* Bucket 0 holds everything under 1 ms, bucket `i` in 1..16 holds
|
|
615
|
+
* `[2^(i-1), 2^i)` ms, and bucket 17 holds everything at or above 65,536 ms.
|
|
616
|
+
* The bounds never move with the data, so two runs' buckets are directly
|
|
617
|
+
* comparable and a readout can draw them without carrying a schema.
|
|
618
|
+
*/
|
|
619
|
+
export const RUNTIME_PHASE_HISTOGRAM_BUCKET_COUNT = 18;
|
|
620
|
+
export const RUNTIME_PHASE_HISTOGRAM_OVERFLOW_LOWER_MS = 65_536;
|
|
621
|
+
|
|
622
|
+
/** The bucket a duration in milliseconds falls in. */
|
|
623
|
+
export function runtimePhaseHistogramBucketIndex(valueMs: number): number {
|
|
624
|
+
if (!(valueMs >= 1)) return 0;
|
|
625
|
+
const floored = Math.floor(valueMs);
|
|
626
|
+
if (floored >= RUNTIME_PHASE_HISTOGRAM_OVERFLOW_LOWER_MS) {
|
|
627
|
+
return RUNTIME_PHASE_HISTOGRAM_BUCKET_COUNT - 1;
|
|
628
|
+
}
|
|
629
|
+
// For a positive 32-bit integer, 32 - clz32(n) is floor(log2(n)) + 1, which
|
|
630
|
+
// is exact where Math.log2 would need a rounding argument at the bounds.
|
|
631
|
+
return 32 - Math.clz32(floored);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/** The half-open `[lowerMs, upperMs)` a bucket covers; the last is open-ended. */
|
|
635
|
+
export function runtimePhaseHistogramBucketBoundsMs(index: number): {
|
|
636
|
+
lowerMs: number;
|
|
637
|
+
upperMs: number | null;
|
|
638
|
+
} {
|
|
639
|
+
if (index <= 0) return { lowerMs: 0, upperMs: 1 };
|
|
640
|
+
if (index >= RUNTIME_PHASE_HISTOGRAM_BUCKET_COUNT - 1) {
|
|
641
|
+
return {
|
|
642
|
+
lowerMs: RUNTIME_PHASE_HISTOGRAM_OVERFLOW_LOWER_MS,
|
|
643
|
+
upperMs: null,
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
return { lowerMs: 2 ** (index - 1), upperMs: 2 ** index };
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* A bucket-resolution percentile estimate over a log2 histogram.
|
|
651
|
+
*
|
|
652
|
+
* Walks the buckets to the one holding rank `quantile * count`, then
|
|
653
|
+
* interpolates linearly across that bucket. The open-ended top bucket
|
|
654
|
+
* interpolates toward the observed maximum, and the estimate is capped at that
|
|
655
|
+
* maximum so a reader never sees a percentile above a value that happened.
|
|
656
|
+
*/
|
|
657
|
+
export function runtimePhaseHistogramPercentileMs(input: {
|
|
658
|
+
buckets: readonly number[];
|
|
659
|
+
count: number;
|
|
660
|
+
maxMs: number | null;
|
|
661
|
+
quantile: number;
|
|
662
|
+
}): number | null {
|
|
663
|
+
if (input.count <= 0) return null;
|
|
664
|
+
const rank = input.quantile * input.count;
|
|
665
|
+
let cumulative = 0;
|
|
666
|
+
for (let index = 0; index < input.buckets.length; index += 1) {
|
|
667
|
+
const bucketCount = input.buckets[index] ?? 0;
|
|
668
|
+
if (bucketCount <= 0) continue;
|
|
669
|
+
if (cumulative + bucketCount < rank) {
|
|
670
|
+
cumulative += bucketCount;
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
const bounds = runtimePhaseHistogramBucketBoundsMs(index);
|
|
674
|
+
const upperMs =
|
|
675
|
+
bounds.upperMs ?? Math.max(bounds.lowerMs, input.maxMs ?? bounds.lowerMs);
|
|
676
|
+
const position = Math.min(
|
|
677
|
+
1,
|
|
678
|
+
Math.max(0, (rank - cumulative) / bucketCount),
|
|
679
|
+
);
|
|
680
|
+
const estimate = bounds.lowerMs + (upperMs - bounds.lowerMs) * position;
|
|
681
|
+
return input.maxMs === null ? estimate : Math.min(estimate, input.maxMs);
|
|
682
|
+
}
|
|
683
|
+
return input.maxMs;
|
|
684
|
+
}
|
|
685
|
+
|
|
49
686
|
export interface RuntimeResourceGovernor {
|
|
50
687
|
acquireRow(input?: {
|
|
51
688
|
estimatedBytes?: number | null;
|
|
@@ -58,10 +695,49 @@ export interface RuntimeResourceGovernor {
|
|
|
58
695
|
estimatedCost?: number | null;
|
|
59
696
|
signal?: AbortSignal;
|
|
60
697
|
}): Promise<RuntimeResourceLease>;
|
|
698
|
+
/** Bound only the active provider execution; the caller owns its budget charge. */
|
|
699
|
+
acquireExternalExecutionSlot(input?: {
|
|
700
|
+
providerResourceKey?: string | null;
|
|
701
|
+
signal?: AbortSignal;
|
|
702
|
+
}): Promise<RuntimeResourceLease>;
|
|
703
|
+
/**
|
|
704
|
+
* Non-blocking external-capacity probe used at a due provider ticket. A
|
|
705
|
+
* caller that misses this probe must re-admit instead of dispatching late.
|
|
706
|
+
*/
|
|
707
|
+
tryAcquireExternalExecutionSlot(input?: {
|
|
708
|
+
providerResourceKey?: string | null;
|
|
709
|
+
}): RuntimeResourceLease | null;
|
|
710
|
+
chargeToolCall(): Promise<void>;
|
|
61
711
|
acquireProviderPermit(input: {
|
|
62
712
|
toolId: string;
|
|
63
713
|
signal?: AbortSignal;
|
|
64
|
-
}): Promise<
|
|
714
|
+
}): Promise<RuntimeProviderPermit>;
|
|
715
|
+
/**
|
|
716
|
+
* Non-blocking provider admission from capacity this process already holds.
|
|
717
|
+
* Safe to probe while holding an external execution slot; null means the
|
|
718
|
+
* caller must release that slot and re-admit through the blocking path.
|
|
719
|
+
*/
|
|
720
|
+
tryAcquireProviderPermit(input: {
|
|
721
|
+
toolId: string;
|
|
722
|
+
}): RuntimeProviderPermit | null;
|
|
723
|
+
/**
|
|
724
|
+
* Observe one physical provider request's run-local residence. This is not
|
|
725
|
+
* a permit: it cannot block, queue, or widen capacity. Callers must release
|
|
726
|
+
* it exactly when the response body is terminal.
|
|
727
|
+
*/
|
|
728
|
+
beginProviderExecution(input: {
|
|
729
|
+
providerResourceKey?: string | null;
|
|
730
|
+
providerTelemetryKey?: string | null;
|
|
731
|
+
}): {
|
|
732
|
+
providerTelemetryKey: string;
|
|
733
|
+
inFlightAtDispatch: number;
|
|
734
|
+
release(): void;
|
|
735
|
+
};
|
|
736
|
+
/**
|
|
737
|
+
* Probe app transport capacity at the physical provider-dispatch edge. A
|
|
738
|
+
* caller that misses it must cancel and re-admit its provider ticket.
|
|
739
|
+
*/
|
|
740
|
+
tryAcquireIntegrationRequestSlot(): RuntimeResourceLease | null;
|
|
65
741
|
suggestedToolParallelism(toolId: string, fallback: number): Promise<number>;
|
|
66
742
|
suggestedDirectToolParallelism(
|
|
67
743
|
toolId: string,
|
|
@@ -72,9 +748,24 @@ export interface RuntimeResourceGovernor {
|
|
|
72
748
|
provider: string;
|
|
73
749
|
toolId?: string;
|
|
74
750
|
retryAfterMs: number;
|
|
751
|
+
/** Provider residence for the rejected physical request, when observed. */
|
|
752
|
+
latencyMs?: number | null;
|
|
753
|
+
/** Server-authored context for attributing this physical provider 429. */
|
|
754
|
+
concurrencyGrant?: ProviderConcurrencyGrant | null;
|
|
75
755
|
}): Promise<void>;
|
|
76
756
|
observe(input: RuntimeResourceObservation): void;
|
|
77
757
|
snapshot(): RuntimeResourceSnapshot;
|
|
758
|
+
/** Stop the event-loop lag sampler. The timer is unref'd either way. */
|
|
759
|
+
stopSampling(): void;
|
|
760
|
+
/** Smoothed event-loop lag from the sampler, or null before its first tick. */
|
|
761
|
+
eventLoopLagEwmaMs(): number | null;
|
|
762
|
+
/** Retain a closed map's admission snapshot for the terminal summary. */
|
|
763
|
+
recordMapAdmission(
|
|
764
|
+
mapName: string,
|
|
765
|
+
snapshot: RuntimeMapHeapAdmissionSnapshot,
|
|
766
|
+
): void;
|
|
767
|
+
/** The byte ledger every retention site registers against, if attached. */
|
|
768
|
+
readonly memoryLedger: RuntimeMemoryLedger | null;
|
|
78
769
|
}
|
|
79
770
|
|
|
80
771
|
type Ewma = {
|
|
@@ -97,10 +788,121 @@ function createEwma(alpha = 0.2): Ewma {
|
|
|
97
788
|
};
|
|
98
789
|
}
|
|
99
790
|
|
|
791
|
+
function createPhaseTiming(): {
|
|
792
|
+
observe(value: number | null | undefined): void;
|
|
793
|
+
snapshot(): RuntimePhaseTiming;
|
|
794
|
+
distribution(): RuntimePhaseDistribution;
|
|
795
|
+
} {
|
|
796
|
+
const ewma = createEwma();
|
|
797
|
+
const buckets = new Array<number>(RUNTIME_PHASE_HISTOGRAM_BUCKET_COUNT).fill(
|
|
798
|
+
0,
|
|
799
|
+
);
|
|
800
|
+
let count = 0;
|
|
801
|
+
let totalMs = 0;
|
|
802
|
+
let maxMs: number | null = null;
|
|
803
|
+
return {
|
|
804
|
+
observe(value) {
|
|
805
|
+
if (value == null || !Number.isFinite(value)) return;
|
|
806
|
+
const normalized = Math.max(0, value);
|
|
807
|
+
count += 1;
|
|
808
|
+
totalMs += normalized;
|
|
809
|
+
maxMs = maxMs === null ? normalized : Math.max(maxMs, normalized);
|
|
810
|
+
ewma.observe(normalized);
|
|
811
|
+
const bucket = runtimePhaseHistogramBucketIndex(normalized);
|
|
812
|
+
buckets[bucket] = (buckets[bucket] ?? 0) + 1;
|
|
813
|
+
},
|
|
814
|
+
snapshot() {
|
|
815
|
+
return { count, totalMs, maxMs, ewmaMs: ewma.value };
|
|
816
|
+
},
|
|
817
|
+
distribution() {
|
|
818
|
+
const percentile = (quantile: number) =>
|
|
819
|
+
runtimePhaseHistogramPercentileMs({
|
|
820
|
+
buckets,
|
|
821
|
+
count,
|
|
822
|
+
maxMs,
|
|
823
|
+
quantile,
|
|
824
|
+
});
|
|
825
|
+
return {
|
|
826
|
+
count,
|
|
827
|
+
totalMs,
|
|
828
|
+
maxMs,
|
|
829
|
+
ewmaMs: ewma.value,
|
|
830
|
+
p50Ms: percentile(0.5),
|
|
831
|
+
p90Ms: percentile(0.9),
|
|
832
|
+
p99Ms: percentile(0.99),
|
|
833
|
+
buckets: buckets.flatMap((bucketCount, index) =>
|
|
834
|
+
bucketCount > 0
|
|
835
|
+
? [[index, bucketCount] as RuntimePhaseHistogramBucket]
|
|
836
|
+
: [],
|
|
837
|
+
),
|
|
838
|
+
};
|
|
839
|
+
},
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
function createSampleTiming(): {
|
|
844
|
+
observe(value: number | null | undefined): void;
|
|
845
|
+
snapshot(): RuntimeSampleTiming;
|
|
846
|
+
} {
|
|
847
|
+
const ewma = createEwma();
|
|
848
|
+
let count = 0;
|
|
849
|
+
let total = 0;
|
|
850
|
+
let max: number | null = null;
|
|
851
|
+
return {
|
|
852
|
+
observe(value) {
|
|
853
|
+
if (value == null || !Number.isFinite(value)) return;
|
|
854
|
+
const normalized = Math.max(0, value);
|
|
855
|
+
count += 1;
|
|
856
|
+
total += normalized;
|
|
857
|
+
max = max === null ? normalized : Math.max(max, normalized);
|
|
858
|
+
ewma.observe(normalized);
|
|
859
|
+
},
|
|
860
|
+
snapshot() {
|
|
861
|
+
return { count, total, max, ewma: ewma.value };
|
|
862
|
+
},
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/** Sampling cadence for runner event-loop lateness. */
|
|
867
|
+
const EVENT_LOOP_LAG_SAMPLE_INTERVAL_MS = 500;
|
|
868
|
+
|
|
100
869
|
function elapsedSince(startedAt: number): number {
|
|
101
870
|
return Math.max(0, Date.now() - startedAt);
|
|
102
871
|
}
|
|
103
872
|
|
|
873
|
+
function readProcessUsage(): RuntimeResourceSnapshot['process'] {
|
|
874
|
+
try {
|
|
875
|
+
const cpu = process.cpuUsage();
|
|
876
|
+
const memory = process.memoryUsage();
|
|
877
|
+
const resources =
|
|
878
|
+
typeof process.resourceUsage === 'function'
|
|
879
|
+
? process.resourceUsage()
|
|
880
|
+
: null;
|
|
881
|
+
const finite = (value: unknown): number | null =>
|
|
882
|
+
typeof value === 'number' && Number.isFinite(value) && value >= 0
|
|
883
|
+
? value
|
|
884
|
+
: null;
|
|
885
|
+
// maxRSS is reported in kibibytes on Linux and bytes on macOS; the sandbox
|
|
886
|
+
// is Linux, and the snapshot names the unit it stores.
|
|
887
|
+
const maxRssRaw = finite(resources?.maxRSS);
|
|
888
|
+
return {
|
|
889
|
+
cpuUserMs: Math.round(cpu.user / 1_000),
|
|
890
|
+
cpuSystemMs: Math.round(cpu.system / 1_000),
|
|
891
|
+
rssBytes: finite(memory.rss),
|
|
892
|
+
maxRssBytes:
|
|
893
|
+
maxRssRaw === null
|
|
894
|
+
? null
|
|
895
|
+
: process.platform === 'darwin'
|
|
896
|
+
? maxRssRaw
|
|
897
|
+
: maxRssRaw * 1024,
|
|
898
|
+
heapUsedBytes: finite(memory.heapUsed),
|
|
899
|
+
externalBytes: finite(memory.external),
|
|
900
|
+
};
|
|
901
|
+
} catch {
|
|
902
|
+
return null;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
104
906
|
function resourceKey(input?: string | null): string {
|
|
105
907
|
const trimmed = input?.trim();
|
|
106
908
|
return trimmed || 'unknown';
|
|
@@ -108,13 +910,129 @@ function resourceKey(input?: string | null): string {
|
|
|
108
910
|
|
|
109
911
|
export function createRuntimeResourceGovernor(input: {
|
|
110
912
|
executionGovernor: PlayExecutionGovernor;
|
|
913
|
+
/**
|
|
914
|
+
* The runtime's byte ledger. Attached by the Play Context so the terminal
|
|
915
|
+
* summary carries what the runner was actually holding, not only what the
|
|
916
|
+
* process happened to report at snapshot time.
|
|
917
|
+
*/
|
|
918
|
+
memoryLedger?: RuntimeMemoryLedger | null;
|
|
111
919
|
}): RuntimeResourceGovernor {
|
|
112
920
|
const rowAdmissionWait = createEwma();
|
|
113
921
|
const toolAdmissionWait = createEwma();
|
|
114
922
|
const sheetFlushLatency = createEwma();
|
|
923
|
+
const phases = {
|
|
924
|
+
rowAdmission: createPhaseTiming(),
|
|
925
|
+
providerAdmission: createPhaseTiming(),
|
|
926
|
+
externalExecution: createPhaseTiming(),
|
|
927
|
+
providerResidence: createPhaseTiming(),
|
|
928
|
+
fixtureDelay: createPhaseTiming(),
|
|
929
|
+
transportSlotWait: createPhaseTiming(),
|
|
930
|
+
fetchToHeaders: createPhaseTiming(),
|
|
931
|
+
bodyRead: createPhaseTiming(),
|
|
932
|
+
eventLoopLag: createPhaseTiming(),
|
|
933
|
+
receiptSettlement: createPhaseTiming(),
|
|
934
|
+
receiptClaim: createPhaseTiming(),
|
|
935
|
+
receiptHydrationGateWait: createPhaseTiming(),
|
|
936
|
+
receiptCompletionQueue: createPhaseTiming(),
|
|
937
|
+
receiptCompletionFlight: createPhaseTiming(),
|
|
938
|
+
receiptCompletionReadBack: createPhaseTiming(),
|
|
939
|
+
rowPersistence: createPhaseTiming(),
|
|
940
|
+
dispatchQueueWait: createPhaseTiming(),
|
|
941
|
+
rowResolverGap: createPhaseTiming(),
|
|
942
|
+
toolCallLogicalWall: createPhaseTiming(),
|
|
943
|
+
resultDelivery: createPhaseTiming(),
|
|
944
|
+
deliveryWrap: createPhaseTiming(),
|
|
945
|
+
deliveryPublishWait: createPhaseTiming(),
|
|
946
|
+
deliveryResolve: createPhaseTiming(),
|
|
947
|
+
flightSerialize: createPhaseTiming(),
|
|
948
|
+
flightTransport: createPhaseTiming(),
|
|
949
|
+
flightDecode: createPhaseTiming(),
|
|
950
|
+
gatewayAuthLaunch: createPhaseTiming(),
|
|
951
|
+
gatewayAuthVerify: createPhaseTiming(),
|
|
952
|
+
gatewayBodyParse: createPhaseTiming(),
|
|
953
|
+
gatewayBodyInflate: createPhaseTiming(),
|
|
954
|
+
gatewayPoolWait: createPhaseTiming(),
|
|
955
|
+
gatewayReceiptValuePersist: createPhaseTiming(),
|
|
956
|
+
gatewayCallback: createPhaseTiming(),
|
|
957
|
+
gatewayRoundTrip: createPhaseTiming(),
|
|
958
|
+
gatewayRequestSerialize: createPhaseTiming(),
|
|
959
|
+
gatewayRequestPack: createPhaseTiming(),
|
|
960
|
+
};
|
|
961
|
+
const executeRoute: RuntimeExecuteRouteTiming = {
|
|
962
|
+
count: 0,
|
|
963
|
+
totalMs: 0,
|
|
964
|
+
chargeOpenMs: 0,
|
|
965
|
+
fixtureLoadMs: 0,
|
|
966
|
+
executeMs: 0,
|
|
967
|
+
};
|
|
968
|
+
const executeChargeOpen = {
|
|
969
|
+
count: 0,
|
|
970
|
+
eligibilityMs: 0,
|
|
971
|
+
capPreflightMs: 0,
|
|
972
|
+
openMutationMs: 0,
|
|
973
|
+
retryWaitMs: 0,
|
|
974
|
+
};
|
|
975
|
+
const executeGateway = {
|
|
976
|
+
count: 0,
|
|
977
|
+
authLaunchMs: 0,
|
|
978
|
+
authVerifyMs: 0,
|
|
979
|
+
bodyParseMs: 0,
|
|
980
|
+
dispatchPoolMs: 0,
|
|
981
|
+
dispatchCallbackMs: 0,
|
|
982
|
+
upstreamHeadersMs: 0,
|
|
983
|
+
upstreamBodyMs: 0,
|
|
984
|
+
};
|
|
985
|
+
const gatewayAuthSessionCounters = {
|
|
986
|
+
hit: 0,
|
|
987
|
+
miss: 0,
|
|
988
|
+
coalesced: 0,
|
|
989
|
+
unknown: 0,
|
|
990
|
+
};
|
|
991
|
+
const gatewayRequestBodyCounters = {
|
|
992
|
+
count: 0,
|
|
993
|
+
rawBytes: 0,
|
|
994
|
+
wireBytes: 0,
|
|
995
|
+
};
|
|
115
996
|
const providers = new Map<
|
|
116
997
|
string,
|
|
117
998
|
{
|
|
999
|
+
admission: ReturnType<typeof createPhaseTiming>;
|
|
1000
|
+
residence: ReturnType<typeof createPhaseTiming>;
|
|
1001
|
+
fixtureDelay: ReturnType<typeof createPhaseTiming>;
|
|
1002
|
+
transportSlotWait: ReturnType<typeof createPhaseTiming>;
|
|
1003
|
+
fetchToHeaders: ReturnType<typeof createPhaseTiming>;
|
|
1004
|
+
bodyRead: ReturnType<typeof createPhaseTiming>;
|
|
1005
|
+
bodyAdmissionWait: ReturnType<typeof createPhaseTiming>;
|
|
1006
|
+
controllerPermits: number;
|
|
1007
|
+
inFlightAtPermit: ReturnType<typeof createSampleTiming>;
|
|
1008
|
+
targetRequestsPerSecond: Ewma;
|
|
1009
|
+
minimumRttMs: Ewma;
|
|
1010
|
+
latency: Ewma;
|
|
1011
|
+
retryAfter: Ewma;
|
|
1012
|
+
provider429Count: number;
|
|
1013
|
+
}
|
|
1014
|
+
>();
|
|
1015
|
+
// This tracker mirrors the capped terminal attribution names. It is a
|
|
1016
|
+
// measurement of work that entered provider residence, not another
|
|
1017
|
+
// admission mechanism. Reservations prevent a burst of distinct providers
|
|
1018
|
+
// from making the tracker grow before their terminal observations arrive.
|
|
1019
|
+
const providerAttributionReservations = new Set<string>();
|
|
1020
|
+
const activeProviderExecutions = new Map<string, number>();
|
|
1021
|
+
const providerAttribution = new Map<
|
|
1022
|
+
string,
|
|
1023
|
+
{
|
|
1024
|
+
admission: ReturnType<typeof createPhaseTiming>;
|
|
1025
|
+
residence: ReturnType<typeof createPhaseTiming>;
|
|
1026
|
+
fixtureDelay: ReturnType<typeof createPhaseTiming>;
|
|
1027
|
+
transportSlotWait: ReturnType<typeof createPhaseTiming>;
|
|
1028
|
+
fetchToHeaders: ReturnType<typeof createPhaseTiming>;
|
|
1029
|
+
bodyRead: ReturnType<typeof createPhaseTiming>;
|
|
1030
|
+
bodyAdmissionWait: ReturnType<typeof createPhaseTiming>;
|
|
1031
|
+
controllerPermits: number;
|
|
1032
|
+
inFlightAtPermit: ReturnType<typeof createSampleTiming>;
|
|
1033
|
+
runInFlightAtDispatch: ReturnType<typeof createSampleTiming>;
|
|
1034
|
+
targetRequestsPerSecond: Ewma;
|
|
1035
|
+
minimumRttMs: Ewma;
|
|
118
1036
|
latency: Ewma;
|
|
119
1037
|
retryAfter: Ewma;
|
|
120
1038
|
provider429Count: number;
|
|
@@ -131,12 +1049,64 @@ export function createRuntimeResourceGovernor(input: {
|
|
|
131
1049
|
acquired: 0,
|
|
132
1050
|
bytes: 0,
|
|
133
1051
|
};
|
|
1052
|
+
const resultEgressCounters = {
|
|
1053
|
+
batches: 0,
|
|
1054
|
+
receipts: 0,
|
|
1055
|
+
bytes: 0,
|
|
1056
|
+
maxBatchBytes: null as number | null,
|
|
1057
|
+
writerPeakInFlightBatches: 0,
|
|
1058
|
+
writerPeakQueued: 0,
|
|
1059
|
+
writerPeakBufferedItems: 0,
|
|
1060
|
+
writerPeakBufferedBytes: 0,
|
|
1061
|
+
readBacks: 0,
|
|
1062
|
+
liveResultReuses: 0,
|
|
1063
|
+
livePublicationResults: 0,
|
|
1064
|
+
existingWinners: 0,
|
|
1065
|
+
legacyAcknowledgements: 0,
|
|
1066
|
+
missingAcknowledgements: 0,
|
|
1067
|
+
nonterminalAcknowledgements: 0,
|
|
1068
|
+
readBackRecovered: 0,
|
|
1069
|
+
readBackMissing: 0,
|
|
1070
|
+
};
|
|
1071
|
+
const concurrencyShedCounters = { count: 0 };
|
|
1072
|
+
const concurrencyShedDelay = createEwma();
|
|
1073
|
+
const mapAdmission: Record<string, RuntimeMapHeapAdmissionSnapshot> = {};
|
|
1074
|
+
|
|
1075
|
+
const readMemorySnapshot = (): RuntimeMemorySnapshot | null => {
|
|
1076
|
+
const ledger = input.memoryLedger?.snapshot();
|
|
1077
|
+
if (!ledger) return null;
|
|
1078
|
+
let admissionHolds = 0;
|
|
1079
|
+
let externalPressureSignals = 0;
|
|
1080
|
+
let memoryPressureEvents = 0;
|
|
1081
|
+
for (const admission of Object.values(mapAdmission)) {
|
|
1082
|
+
admissionHolds += admission.admissionHolds;
|
|
1083
|
+
externalPressureSignals += admission.externalPressureSignals;
|
|
1084
|
+
memoryPressureEvents += admission.memoryPressureEvents;
|
|
1085
|
+
}
|
|
1086
|
+
return {
|
|
1087
|
+
...ledger,
|
|
1088
|
+
admissionHolds,
|
|
1089
|
+
externalPressureSignals,
|
|
1090
|
+
memoryPressureEvents,
|
|
1091
|
+
};
|
|
1092
|
+
};
|
|
134
1093
|
|
|
135
1094
|
const providerStats = (key: string) => {
|
|
136
1095
|
const normalized = resourceKey(key);
|
|
137
1096
|
let stats = providers.get(normalized);
|
|
138
1097
|
if (!stats) {
|
|
139
1098
|
stats = {
|
|
1099
|
+
admission: createPhaseTiming(),
|
|
1100
|
+
residence: createPhaseTiming(),
|
|
1101
|
+
fixtureDelay: createPhaseTiming(),
|
|
1102
|
+
transportSlotWait: createPhaseTiming(),
|
|
1103
|
+
fetchToHeaders: createPhaseTiming(),
|
|
1104
|
+
bodyRead: createPhaseTiming(),
|
|
1105
|
+
bodyAdmissionWait: createPhaseTiming(),
|
|
1106
|
+
controllerPermits: 0,
|
|
1107
|
+
inFlightAtPermit: createSampleTiming(),
|
|
1108
|
+
targetRequestsPerSecond: createEwma(),
|
|
1109
|
+
minimumRttMs: createEwma(),
|
|
140
1110
|
latency: createEwma(),
|
|
141
1111
|
retryAfter: createEwma(),
|
|
142
1112
|
provider429Count: 0,
|
|
@@ -146,10 +1116,314 @@ export function createRuntimeResourceGovernor(input: {
|
|
|
146
1116
|
return stats;
|
|
147
1117
|
};
|
|
148
1118
|
|
|
1119
|
+
const providerAttributionKey = (key: string): string => {
|
|
1120
|
+
const normalized = resourceKey(key);
|
|
1121
|
+
if (
|
|
1122
|
+
normalized === PROVIDER_ATTRIBUTION_OTHER_KEY ||
|
|
1123
|
+
providerAttribution.has(normalized) ||
|
|
1124
|
+
providerAttributionReservations.has(normalized)
|
|
1125
|
+
) {
|
|
1126
|
+
return normalized;
|
|
1127
|
+
}
|
|
1128
|
+
const namedCount = new Set([
|
|
1129
|
+
...[...providerAttribution.keys()].filter(
|
|
1130
|
+
(provider) => provider !== PROVIDER_ATTRIBUTION_OTHER_KEY,
|
|
1131
|
+
),
|
|
1132
|
+
...providerAttributionReservations,
|
|
1133
|
+
]).size;
|
|
1134
|
+
if (namedCount >= MAX_PROVIDER_ATTRIBUTION_BUCKETS) {
|
|
1135
|
+
return PROVIDER_ATTRIBUTION_OTHER_KEY;
|
|
1136
|
+
}
|
|
1137
|
+
providerAttributionReservations.add(normalized);
|
|
1138
|
+
return normalized;
|
|
1139
|
+
};
|
|
1140
|
+
|
|
1141
|
+
const providerAttributionStats = (key: string) => {
|
|
1142
|
+
const attributionKey = providerAttributionKey(key);
|
|
1143
|
+
let stats = providerAttribution.get(attributionKey);
|
|
1144
|
+
if (!stats) {
|
|
1145
|
+
stats = {
|
|
1146
|
+
admission: createPhaseTiming(),
|
|
1147
|
+
residence: createPhaseTiming(),
|
|
1148
|
+
fixtureDelay: createPhaseTiming(),
|
|
1149
|
+
transportSlotWait: createPhaseTiming(),
|
|
1150
|
+
fetchToHeaders: createPhaseTiming(),
|
|
1151
|
+
bodyRead: createPhaseTiming(),
|
|
1152
|
+
bodyAdmissionWait: createPhaseTiming(),
|
|
1153
|
+
controllerPermits: 0,
|
|
1154
|
+
inFlightAtPermit: createSampleTiming(),
|
|
1155
|
+
runInFlightAtDispatch: createSampleTiming(),
|
|
1156
|
+
targetRequestsPerSecond: createEwma(),
|
|
1157
|
+
minimumRttMs: createEwma(),
|
|
1158
|
+
latency: createEwma(),
|
|
1159
|
+
retryAfter: createEwma(),
|
|
1160
|
+
provider429Count: 0,
|
|
1161
|
+
};
|
|
1162
|
+
providerAttribution.set(attributionKey, stats);
|
|
1163
|
+
}
|
|
1164
|
+
return stats;
|
|
1165
|
+
};
|
|
1166
|
+
|
|
1167
|
+
const observeProviderStats = (
|
|
1168
|
+
stats: {
|
|
1169
|
+
admission: ReturnType<typeof createPhaseTiming>;
|
|
1170
|
+
residence: ReturnType<typeof createPhaseTiming>;
|
|
1171
|
+
fixtureDelay: ReturnType<typeof createPhaseTiming>;
|
|
1172
|
+
transportSlotWait: ReturnType<typeof createPhaseTiming>;
|
|
1173
|
+
fetchToHeaders: ReturnType<typeof createPhaseTiming>;
|
|
1174
|
+
bodyRead: ReturnType<typeof createPhaseTiming>;
|
|
1175
|
+
bodyAdmissionWait: ReturnType<typeof createPhaseTiming>;
|
|
1176
|
+
controllerPermits: number;
|
|
1177
|
+
inFlightAtPermit: ReturnType<typeof createSampleTiming>;
|
|
1178
|
+
runInFlightAtDispatch?: ReturnType<typeof createSampleTiming>;
|
|
1179
|
+
targetRequestsPerSecond: Ewma;
|
|
1180
|
+
minimumRttMs: Ewma;
|
|
1181
|
+
latency: Ewma;
|
|
1182
|
+
retryAfter: Ewma;
|
|
1183
|
+
provider429Count: number;
|
|
1184
|
+
},
|
|
1185
|
+
observation: RuntimeResourceObservation,
|
|
1186
|
+
) => {
|
|
1187
|
+
stats.admission.observe(observation.providerAdmissionWaitMs);
|
|
1188
|
+
stats.residence.observe(observation.providerLatencyMs);
|
|
1189
|
+
stats.fixtureDelay.observe(observation.fixtureDelayMs);
|
|
1190
|
+
stats.transportSlotWait.observe(observation.transportSlotWaitMs);
|
|
1191
|
+
stats.fetchToHeaders.observe(observation.fetchToHeadersMs);
|
|
1192
|
+
stats.bodyRead.observe(observation.bodyReadMs);
|
|
1193
|
+
stats.bodyAdmissionWait.observe(observation.providerBodyAdmissionWaitMs);
|
|
1194
|
+
const pacingGrant =
|
|
1195
|
+
observation.providerPacingGrant ?? observation.providerConcurrencyGrant;
|
|
1196
|
+
if (pacingGrant) {
|
|
1197
|
+
stats.controllerPermits += 1;
|
|
1198
|
+
stats.targetRequestsPerSecond.observe(
|
|
1199
|
+
pacingGrant.targetRequestsPerSecond,
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
const concurrencyGrant = observation.providerConcurrencyGrant;
|
|
1203
|
+
if (concurrencyGrant) {
|
|
1204
|
+
stats.inFlightAtPermit.observe(concurrencyGrant.inFlightAtStart);
|
|
1205
|
+
stats.minimumRttMs.observe(concurrencyGrant.minimumRttMs);
|
|
1206
|
+
}
|
|
1207
|
+
stats.runInFlightAtDispatch?.observe(
|
|
1208
|
+
observation.providerRunInFlightAtDispatch,
|
|
1209
|
+
);
|
|
1210
|
+
stats.latency.observe(observation.providerLatencyMs);
|
|
1211
|
+
stats.retryAfter.observe(observation.retryAfterMs);
|
|
1212
|
+
if (observation.provider429) {
|
|
1213
|
+
stats.provider429Count += 1;
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
|
|
1217
|
+
let eventLoopLagTimer: ReturnType<typeof setInterval> | null = null;
|
|
1218
|
+
let eventLoopLagTickedAt: number | null = null;
|
|
1219
|
+
const startEventLoopLagSampler = (): void => {
|
|
1220
|
+
if (eventLoopLagTimer !== null) return;
|
|
1221
|
+
eventLoopLagTickedAt = Date.now();
|
|
1222
|
+
eventLoopLagTimer = setInterval(() => {
|
|
1223
|
+
const now = Date.now();
|
|
1224
|
+
const dueAt =
|
|
1225
|
+
(eventLoopLagTickedAt ?? now) + EVENT_LOOP_LAG_SAMPLE_INTERVAL_MS;
|
|
1226
|
+
eventLoopLagTickedAt = now;
|
|
1227
|
+
phases.eventLoopLag.observe(Math.max(0, now - dueAt));
|
|
1228
|
+
}, EVENT_LOOP_LAG_SAMPLE_INTERVAL_MS);
|
|
1229
|
+
// Measurement must never hold a runner open past its work.
|
|
1230
|
+
const handle = eventLoopLagTimer as { unref?: () => void };
|
|
1231
|
+
if (typeof handle.unref === 'function') {
|
|
1232
|
+
handle.unref();
|
|
1233
|
+
}
|
|
1234
|
+
};
|
|
1235
|
+
const stopEventLoopLagSampler = (): void => {
|
|
1236
|
+
if (eventLoopLagTimer === null) return;
|
|
1237
|
+
clearInterval(eventLoopLagTimer);
|
|
1238
|
+
eventLoopLagTimer = null;
|
|
1239
|
+
eventLoopLagTickedAt = null;
|
|
1240
|
+
};
|
|
1241
|
+
|
|
149
1242
|
const observe = (observation: RuntimeResourceObservation): void => {
|
|
1243
|
+
startEventLoopLagSampler();
|
|
150
1244
|
rowAdmissionWait.observe(observation.rowAdmissionWaitMs);
|
|
151
1245
|
toolAdmissionWait.observe(observation.toolAdmissionWaitMs);
|
|
152
1246
|
sheetFlushLatency.observe(observation.sheetFlushLatencyMs);
|
|
1247
|
+
phases.rowAdmission.observe(observation.rowAdmissionWaitMs);
|
|
1248
|
+
phases.providerAdmission.observe(observation.providerAdmissionWaitMs);
|
|
1249
|
+
phases.externalExecution.observe(observation.externalExecutionWaitMs);
|
|
1250
|
+
phases.providerResidence.observe(observation.providerLatencyMs);
|
|
1251
|
+
phases.fixtureDelay.observe(observation.fixtureDelayMs);
|
|
1252
|
+
phases.transportSlotWait.observe(observation.transportSlotWaitMs);
|
|
1253
|
+
phases.fetchToHeaders.observe(observation.fetchToHeadersMs);
|
|
1254
|
+
const executeRouteTiming = observation.executeServerTiming;
|
|
1255
|
+
// The response writer emits every named stage. Refuse a partial header so
|
|
1256
|
+
// this compact run aggregate has one honest denominator rather than four
|
|
1257
|
+
// incomparable ones from a rolling app/runtime skew.
|
|
1258
|
+
if (
|
|
1259
|
+
executeRouteTiming != null &&
|
|
1260
|
+
typeof executeRouteTiming.total === 'number' &&
|
|
1261
|
+
typeof executeRouteTiming.charge_open === 'number' &&
|
|
1262
|
+
typeof executeRouteTiming.fixture_load === 'number' &&
|
|
1263
|
+
typeof executeRouteTiming.execute === 'number'
|
|
1264
|
+
) {
|
|
1265
|
+
executeRoute.count += 1;
|
|
1266
|
+
executeRoute.totalMs += executeRouteTiming.total;
|
|
1267
|
+
executeRoute.chargeOpenMs += executeRouteTiming.charge_open;
|
|
1268
|
+
executeRoute.fixtureLoadMs += executeRouteTiming.fixture_load;
|
|
1269
|
+
executeRoute.executeMs += executeRouteTiming.execute;
|
|
1270
|
+
// Same rule as the gateway block below: require the complete substage
|
|
1271
|
+
// set this app version emits, so an older build that reports only
|
|
1272
|
+
// `charge_open` does not silently contribute a partial split.
|
|
1273
|
+
if (
|
|
1274
|
+
typeof executeRouteTiming.charge_eligibility === 'number' &&
|
|
1275
|
+
typeof executeRouteTiming.charge_cap_preflight === 'number' &&
|
|
1276
|
+
typeof executeRouteTiming.charge_open_mutation === 'number' &&
|
|
1277
|
+
typeof executeRouteTiming.charge_retry_wait === 'number'
|
|
1278
|
+
) {
|
|
1279
|
+
executeChargeOpen.count += 1;
|
|
1280
|
+
executeChargeOpen.eligibilityMs +=
|
|
1281
|
+
executeRouteTiming.charge_eligibility;
|
|
1282
|
+
executeChargeOpen.capPreflightMs +=
|
|
1283
|
+
executeRouteTiming.charge_cap_preflight;
|
|
1284
|
+
executeChargeOpen.openMutationMs +=
|
|
1285
|
+
executeRouteTiming.charge_open_mutation;
|
|
1286
|
+
executeChargeOpen.retryWaitMs += executeRouteTiming.charge_retry_wait;
|
|
1287
|
+
}
|
|
1288
|
+
// Gateway timing is a separate request-owner clock, but it is retained
|
|
1289
|
+
// only for the exact handler population above. Some routed tools have
|
|
1290
|
+
// the relay header but no app execute split; mixing them would make
|
|
1291
|
+
// `upstream_headers - handler.total` mathematically meaningless.
|
|
1292
|
+
// Require the complete set that this gateway version emits too, so a
|
|
1293
|
+
// rolling deploy cannot create a misleading sum over a different
|
|
1294
|
+
// population.
|
|
1295
|
+
if (
|
|
1296
|
+
typeof executeRouteTiming.auth_launch === 'number' &&
|
|
1297
|
+
typeof executeRouteTiming.auth_verify === 'number' &&
|
|
1298
|
+
typeof executeRouteTiming.body_parse === 'number' &&
|
|
1299
|
+
typeof executeRouteTiming.dispatch_pool === 'number' &&
|
|
1300
|
+
typeof executeRouteTiming.dispatch_callback === 'number' &&
|
|
1301
|
+
typeof executeRouteTiming.upstream_headers === 'number' &&
|
|
1302
|
+
typeof executeRouteTiming.upstream_body === 'number'
|
|
1303
|
+
) {
|
|
1304
|
+
executeGateway.count += 1;
|
|
1305
|
+
executeGateway.authLaunchMs += executeRouteTiming.auth_launch;
|
|
1306
|
+
executeGateway.authVerifyMs += executeRouteTiming.auth_verify;
|
|
1307
|
+
executeGateway.bodyParseMs += executeRouteTiming.body_parse;
|
|
1308
|
+
executeGateway.dispatchPoolMs += executeRouteTiming.dispatch_pool;
|
|
1309
|
+
executeGateway.dispatchCallbackMs +=
|
|
1310
|
+
executeRouteTiming.dispatch_callback;
|
|
1311
|
+
executeGateway.upstreamHeadersMs += executeRouteTiming.upstream_headers;
|
|
1312
|
+
executeGateway.upstreamBodyMs += executeRouteTiming.upstream_body;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
phases.bodyRead.observe(observation.bodyReadMs);
|
|
1316
|
+
phases.receiptSettlement.observe(observation.receiptLatencyMs);
|
|
1317
|
+
phases.receiptClaim.observe(observation.receiptClaimMs);
|
|
1318
|
+
phases.receiptHydrationGateWait.observe(
|
|
1319
|
+
observation.receiptHydrationGateWaitMs,
|
|
1320
|
+
);
|
|
1321
|
+
phases.receiptCompletionQueue.observe(observation.receiptCompletionQueueMs);
|
|
1322
|
+
phases.receiptCompletionFlight.observe(
|
|
1323
|
+
observation.receiptCompletionFlightMs,
|
|
1324
|
+
);
|
|
1325
|
+
phases.receiptCompletionReadBack.observe(
|
|
1326
|
+
observation.receiptCompletionReadBackMs,
|
|
1327
|
+
);
|
|
1328
|
+
phases.rowPersistence.observe(observation.sheetFlushLatencyMs);
|
|
1329
|
+
phases.dispatchQueueWait.observe(observation.dispatchQueueWaitMs);
|
|
1330
|
+
phases.rowResolverGap.observe(observation.rowResolverGapMs);
|
|
1331
|
+
phases.toolCallLogicalWall.observe(observation.toolCallLogicalWallMs);
|
|
1332
|
+
phases.resultDelivery.observe(observation.resultDeliveryMs);
|
|
1333
|
+
phases.deliveryWrap.observe(observation.deliveryWrapMs);
|
|
1334
|
+
phases.deliveryPublishWait.observe(observation.deliveryPublishWaitMs);
|
|
1335
|
+
phases.deliveryResolve.observe(observation.deliveryResolveMs);
|
|
1336
|
+
phases.flightSerialize.observe(observation.flightSerializeMs);
|
|
1337
|
+
phases.flightTransport.observe(observation.flightTransportMs);
|
|
1338
|
+
phases.flightDecode.observe(observation.flightDecodeMs);
|
|
1339
|
+
phases.gatewayAuthLaunch.observe(observation.gatewayAuthLaunchMs);
|
|
1340
|
+
phases.gatewayAuthVerify.observe(observation.gatewayAuthVerifyMs);
|
|
1341
|
+
phases.gatewayBodyParse.observe(observation.gatewayBodyParseMs);
|
|
1342
|
+
phases.gatewayBodyInflate.observe(observation.gatewayBodyInflateMs);
|
|
1343
|
+
phases.gatewayPoolWait.observe(observation.gatewayPoolWaitMs);
|
|
1344
|
+
phases.gatewayReceiptValuePersist.observe(
|
|
1345
|
+
observation.gatewayReceiptValuePersistMs,
|
|
1346
|
+
);
|
|
1347
|
+
phases.gatewayCallback.observe(observation.gatewayCallbackMs);
|
|
1348
|
+
phases.gatewayRoundTrip.observe(observation.gatewayRoundTripMs);
|
|
1349
|
+
phases.gatewayRequestSerialize.observe(
|
|
1350
|
+
observation.gatewayRequestSerializeMs,
|
|
1351
|
+
);
|
|
1352
|
+
phases.gatewayRequestPack.observe(observation.gatewayRequestPackMs);
|
|
1353
|
+
if (observation.gatewayAuthSession != null) {
|
|
1354
|
+
gatewayAuthSessionCounters[observation.gatewayAuthSession] += 1;
|
|
1355
|
+
}
|
|
1356
|
+
// Raw is the authority for the count: every request has serialized bytes,
|
|
1357
|
+
// so a missing wire size (an older transport) adds nothing rather than
|
|
1358
|
+
// silently reporting a request that moved zero bytes.
|
|
1359
|
+
if (observation.gatewayRequestRawBytes != null) {
|
|
1360
|
+
gatewayRequestBodyCounters.count += 1;
|
|
1361
|
+
gatewayRequestBodyCounters.rawBytes += Math.max(
|
|
1362
|
+
0,
|
|
1363
|
+
Math.floor(observation.gatewayRequestRawBytes),
|
|
1364
|
+
);
|
|
1365
|
+
gatewayRequestBodyCounters.wireBytes += Math.max(
|
|
1366
|
+
0,
|
|
1367
|
+
Math.floor(
|
|
1368
|
+
observation.gatewayRequestWireBytes ??
|
|
1369
|
+
observation.gatewayRequestRawBytes,
|
|
1370
|
+
),
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
if (observation.receiptCompletionReadBacks != null) {
|
|
1374
|
+
resultEgressCounters.readBacks += Math.max(
|
|
1375
|
+
0,
|
|
1376
|
+
Math.floor(observation.receiptCompletionReadBacks),
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
if (observation.receiptCompletionLiveResultReuses != null) {
|
|
1380
|
+
resultEgressCounters.liveResultReuses += Math.max(
|
|
1381
|
+
0,
|
|
1382
|
+
Math.floor(observation.receiptCompletionLiveResultReuses),
|
|
1383
|
+
);
|
|
1384
|
+
}
|
|
1385
|
+
if (observation.receiptCompletionLivePublicationResults != null) {
|
|
1386
|
+
resultEgressCounters.livePublicationResults += Math.max(
|
|
1387
|
+
0,
|
|
1388
|
+
Math.floor(observation.receiptCompletionLivePublicationResults),
|
|
1389
|
+
);
|
|
1390
|
+
}
|
|
1391
|
+
if (observation.receiptCompletionExistingWinners != null) {
|
|
1392
|
+
resultEgressCounters.existingWinners += Math.max(
|
|
1393
|
+
0,
|
|
1394
|
+
Math.floor(observation.receiptCompletionExistingWinners),
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
if (observation.receiptCompletionLegacyAcknowledgements != null) {
|
|
1398
|
+
resultEgressCounters.legacyAcknowledgements += Math.max(
|
|
1399
|
+
0,
|
|
1400
|
+
Math.floor(observation.receiptCompletionLegacyAcknowledgements),
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
if (observation.receiptCompletionMissingAcknowledgements != null) {
|
|
1404
|
+
resultEgressCounters.missingAcknowledgements += Math.max(
|
|
1405
|
+
0,
|
|
1406
|
+
Math.floor(observation.receiptCompletionMissingAcknowledgements),
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
if (observation.receiptCompletionNonterminalAcknowledgements != null) {
|
|
1410
|
+
resultEgressCounters.nonterminalAcknowledgements += Math.max(
|
|
1411
|
+
0,
|
|
1412
|
+
Math.floor(observation.receiptCompletionNonterminalAcknowledgements),
|
|
1413
|
+
);
|
|
1414
|
+
}
|
|
1415
|
+
if (observation.receiptCompletionReadBackRecovered != null) {
|
|
1416
|
+
resultEgressCounters.readBackRecovered += Math.max(
|
|
1417
|
+
0,
|
|
1418
|
+
Math.floor(observation.receiptCompletionReadBackRecovered),
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
if (observation.receiptCompletionReadBackMissing != null) {
|
|
1422
|
+
resultEgressCounters.readBackMissing += Math.max(
|
|
1423
|
+
0,
|
|
1424
|
+
Math.floor(observation.receiptCompletionReadBackMissing),
|
|
1425
|
+
);
|
|
1426
|
+
}
|
|
153
1427
|
if (observation.sheetFlushLatencyMs != null) {
|
|
154
1428
|
sheetFlushCounters.acquired += 1;
|
|
155
1429
|
}
|
|
@@ -165,17 +1439,72 @@ export function createRuntimeResourceGovernor(input: {
|
|
|
165
1439
|
Math.floor(observation.sheetFlushBytes),
|
|
166
1440
|
);
|
|
167
1441
|
}
|
|
168
|
-
if (
|
|
1442
|
+
if (observation.receiptEgressBatchSize != null) {
|
|
1443
|
+
resultEgressCounters.batches += 1;
|
|
1444
|
+
resultEgressCounters.receipts += Math.max(
|
|
1445
|
+
0,
|
|
1446
|
+
Math.floor(observation.receiptEgressBatchSize),
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
if (observation.receiptEgressBytes != null) {
|
|
1450
|
+
const bytes = Math.max(0, Math.floor(observation.receiptEgressBytes));
|
|
1451
|
+
resultEgressCounters.bytes += bytes;
|
|
1452
|
+
resultEgressCounters.maxBatchBytes =
|
|
1453
|
+
resultEgressCounters.maxBatchBytes === null
|
|
1454
|
+
? bytes
|
|
1455
|
+
: Math.max(resultEgressCounters.maxBatchBytes, bytes);
|
|
1456
|
+
}
|
|
1457
|
+
if (observation.receiptCompletionWriterInFlightBatches != null) {
|
|
1458
|
+
resultEgressCounters.writerPeakInFlightBatches = Math.max(
|
|
1459
|
+
resultEgressCounters.writerPeakInFlightBatches,
|
|
1460
|
+
Math.max(
|
|
1461
|
+
0,
|
|
1462
|
+
Math.floor(observation.receiptCompletionWriterInFlightBatches),
|
|
1463
|
+
),
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
1466
|
+
if (observation.receiptCompletionWriterQueued != null) {
|
|
1467
|
+
resultEgressCounters.writerPeakQueued = Math.max(
|
|
1468
|
+
resultEgressCounters.writerPeakQueued,
|
|
1469
|
+
Math.max(0, Math.floor(observation.receiptCompletionWriterQueued)),
|
|
1470
|
+
);
|
|
1471
|
+
}
|
|
1472
|
+
if (observation.receiptCompletionWriterBufferedItems != null) {
|
|
1473
|
+
resultEgressCounters.writerPeakBufferedItems = Math.max(
|
|
1474
|
+
resultEgressCounters.writerPeakBufferedItems,
|
|
1475
|
+
Math.max(
|
|
1476
|
+
0,
|
|
1477
|
+
Math.floor(observation.receiptCompletionWriterBufferedItems),
|
|
1478
|
+
),
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1481
|
+
if (observation.receiptCompletionWriterBufferedBytes != null) {
|
|
1482
|
+
resultEgressCounters.writerPeakBufferedBytes = Math.max(
|
|
1483
|
+
resultEgressCounters.writerPeakBufferedBytes,
|
|
1484
|
+
Math.max(
|
|
1485
|
+
0,
|
|
1486
|
+
Math.floor(observation.receiptCompletionWriterBufferedBytes),
|
|
1487
|
+
),
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
if (observation.concurrencyShedDelayMs != null) {
|
|
1491
|
+
concurrencyShedCounters.count += 1;
|
|
1492
|
+
concurrencyShedDelay.observe(observation.concurrencyShedDelayMs);
|
|
1493
|
+
}
|
|
1494
|
+
const hasProviderObservation =
|
|
169
1495
|
observation.providerResourceKey ||
|
|
1496
|
+
observation.providerTelemetryKey ||
|
|
170
1497
|
observation.providerLatencyMs != null ||
|
|
171
1498
|
observation.provider429 ||
|
|
172
|
-
observation.retryAfterMs != null
|
|
173
|
-
) {
|
|
1499
|
+
observation.retryAfterMs != null;
|
|
1500
|
+
if (hasProviderObservation) {
|
|
174
1501
|
const stats = providerStats(observation.providerResourceKey ?? 'unknown');
|
|
175
|
-
stats
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
1502
|
+
observeProviderStats(stats, observation);
|
|
1503
|
+
if (observation.providerTelemetryKey) {
|
|
1504
|
+
observeProviderStats(
|
|
1505
|
+
providerAttributionStats(observation.providerTelemetryKey),
|
|
1506
|
+
observation,
|
|
1507
|
+
);
|
|
179
1508
|
}
|
|
180
1509
|
if (
|
|
181
1510
|
observation.providerSuccess === true &&
|
|
@@ -226,11 +1555,90 @@ export function createRuntimeResourceGovernor(input: {
|
|
|
226
1555
|
return lease;
|
|
227
1556
|
},
|
|
228
1557
|
|
|
229
|
-
|
|
230
|
-
|
|
1558
|
+
async acquireExternalExecutionSlot(slotInput) {
|
|
1559
|
+
const startedAt = Date.now();
|
|
1560
|
+
const lease = await input.executionGovernor.acquireToolExecutionSlot({
|
|
1561
|
+
signal: slotInput?.signal,
|
|
1562
|
+
});
|
|
1563
|
+
toolCounters.acquired += 1;
|
|
1564
|
+
observe({
|
|
1565
|
+
providerResourceKey: slotInput?.providerResourceKey ?? null,
|
|
1566
|
+
externalExecutionWaitMs: elapsedSince(startedAt),
|
|
1567
|
+
});
|
|
1568
|
+
return lease;
|
|
1569
|
+
},
|
|
1570
|
+
|
|
1571
|
+
tryAcquireExternalExecutionSlot(slotInput) {
|
|
1572
|
+
const lease = input.executionGovernor.tryAcquireToolExecutionSlot();
|
|
1573
|
+
if (!lease) return null;
|
|
1574
|
+
toolCounters.acquired += 1;
|
|
1575
|
+
observe({
|
|
1576
|
+
providerResourceKey: slotInput?.providerResourceKey ?? null,
|
|
1577
|
+
externalExecutionWaitMs: 0,
|
|
1578
|
+
});
|
|
1579
|
+
return lease;
|
|
1580
|
+
},
|
|
1581
|
+
|
|
1582
|
+
chargeToolCall: () => input.executionGovernor.chargeBudget('toolCall'),
|
|
1583
|
+
|
|
1584
|
+
async acquireProviderPermit(providerInput) {
|
|
1585
|
+
const startedAt = Date.now();
|
|
1586
|
+
const lease = await input.executionGovernor.acquireProviderPermit(
|
|
231
1587
|
providerInput.toolId,
|
|
232
1588
|
{ signal: providerInput.signal },
|
|
233
1589
|
);
|
|
1590
|
+
observe({
|
|
1591
|
+
providerResourceKey: lease.provider,
|
|
1592
|
+
providerTelemetryKey: lease.provider,
|
|
1593
|
+
providerAdmissionWaitMs: elapsedSince(startedAt),
|
|
1594
|
+
});
|
|
1595
|
+
return lease;
|
|
1596
|
+
},
|
|
1597
|
+
|
|
1598
|
+
tryAcquireProviderPermit(providerInput) {
|
|
1599
|
+
const lease = input.executionGovernor.tryAcquireProviderPermit(
|
|
1600
|
+
providerInput.toolId,
|
|
1601
|
+
);
|
|
1602
|
+
if (!lease) return null;
|
|
1603
|
+
observe({
|
|
1604
|
+
providerResourceKey: lease.provider,
|
|
1605
|
+
providerTelemetryKey: lease.provider,
|
|
1606
|
+
providerAdmissionWaitMs: 0,
|
|
1607
|
+
});
|
|
1608
|
+
return lease;
|
|
1609
|
+
},
|
|
1610
|
+
|
|
1611
|
+
beginProviderExecution(providerInput) {
|
|
1612
|
+
const providerTelemetryKey = providerAttributionKey(
|
|
1613
|
+
providerInput.providerTelemetryKey ??
|
|
1614
|
+
providerInput.providerResourceKey ??
|
|
1615
|
+
'unknown',
|
|
1616
|
+
);
|
|
1617
|
+
const inFlightAtDispatch =
|
|
1618
|
+
activeProviderExecutions.get(providerTelemetryKey) ?? 0;
|
|
1619
|
+
activeProviderExecutions.set(
|
|
1620
|
+
providerTelemetryKey,
|
|
1621
|
+
inFlightAtDispatch + 1,
|
|
1622
|
+
);
|
|
1623
|
+
let released = false;
|
|
1624
|
+
return {
|
|
1625
|
+
providerTelemetryKey,
|
|
1626
|
+
inFlightAtDispatch,
|
|
1627
|
+
release() {
|
|
1628
|
+
if (released) return;
|
|
1629
|
+
released = true;
|
|
1630
|
+
const active = activeProviderExecutions.get(providerTelemetryKey);
|
|
1631
|
+
if (!active || active <= 1) {
|
|
1632
|
+
activeProviderExecutions.delete(providerTelemetryKey);
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
activeProviderExecutions.set(providerTelemetryKey, active - 1);
|
|
1636
|
+
},
|
|
1637
|
+
};
|
|
1638
|
+
},
|
|
1639
|
+
|
|
1640
|
+
tryAcquireIntegrationRequestSlot() {
|
|
1641
|
+
return input.executionGovernor.tryAcquireIntegrationRequestSlot();
|
|
234
1642
|
},
|
|
235
1643
|
|
|
236
1644
|
suggestedToolParallelism(toolId, fallback) {
|
|
@@ -259,8 +1667,91 @@ export function createRuntimeResourceGovernor(input: {
|
|
|
259
1667
|
|
|
260
1668
|
observe,
|
|
261
1669
|
|
|
1670
|
+
stopSampling: stopEventLoopLagSampler,
|
|
1671
|
+
eventLoopLagEwmaMs: () => phases.eventLoopLag.snapshot().ewmaMs,
|
|
1672
|
+
|
|
1673
|
+
recordMapAdmission(mapName, snapshot) {
|
|
1674
|
+
// The ledger is per-process, not per-map: the runner publishes it once
|
|
1675
|
+
// under `memory` below. Repeating it inside every map's admission
|
|
1676
|
+
// snapshot only spends the terminal metadata budget, and a
|
|
1677
|
+
// runtimeResources record over that budget is dropped whole.
|
|
1678
|
+
mapAdmission[resourceKey(mapName)] = { ...snapshot, memory: null };
|
|
1679
|
+
},
|
|
1680
|
+
|
|
1681
|
+
memoryLedger: input.memoryLedger ?? null,
|
|
1682
|
+
|
|
262
1683
|
snapshot() {
|
|
263
1684
|
return {
|
|
1685
|
+
// At the capped mixed-provider maximum, preserve the controller and
|
|
1686
|
+
// residence table rather than risking the terminal envelope for a
|
|
1687
|
+
// secondary diagnostic. Normal fixture shapes retain this aggregate.
|
|
1688
|
+
...(executeRoute.count > 0 &&
|
|
1689
|
+
providerAttribution.size < MAX_PROVIDER_ATTRIBUTION_BUCKETS
|
|
1690
|
+
? {
|
|
1691
|
+
executeRoute: {
|
|
1692
|
+
...executeRoute,
|
|
1693
|
+
...(executeChargeOpen.count > 0
|
|
1694
|
+
? { chargeOpen: { ...executeChargeOpen } }
|
|
1695
|
+
: {}),
|
|
1696
|
+
...(executeGateway.count > 0
|
|
1697
|
+
? { gateway: { ...executeGateway } }
|
|
1698
|
+
: {}),
|
|
1699
|
+
},
|
|
1700
|
+
}
|
|
1701
|
+
: {}),
|
|
1702
|
+
process: readProcessUsage(),
|
|
1703
|
+
mapAdmission: { ...mapAdmission },
|
|
1704
|
+
memory: readMemorySnapshot(),
|
|
1705
|
+
// Distributions ride only on the run-level phases. Per-provider
|
|
1706
|
+
// timings stay lean counters: the provider map is unbounded, and the
|
|
1707
|
+
// terminal metadata record is dropped whole once it passes its budget.
|
|
1708
|
+
phases: {
|
|
1709
|
+
rowAdmission: phases.rowAdmission.distribution(),
|
|
1710
|
+
providerAdmission: phases.providerAdmission.distribution(),
|
|
1711
|
+
externalExecution: phases.externalExecution.distribution(),
|
|
1712
|
+
providerResidence: phases.providerResidence.distribution(),
|
|
1713
|
+
fixtureDelay: phases.fixtureDelay.distribution(),
|
|
1714
|
+
transportSlotWait: phases.transportSlotWait.distribution(),
|
|
1715
|
+
fetchToHeaders: phases.fetchToHeaders.distribution(),
|
|
1716
|
+
bodyRead: phases.bodyRead.distribution(),
|
|
1717
|
+
eventLoopLag: phases.eventLoopLag.distribution(),
|
|
1718
|
+
receiptSettlement: phases.receiptSettlement.distribution(),
|
|
1719
|
+
receiptClaim: phases.receiptClaim.distribution(),
|
|
1720
|
+
receiptHydrationGateWait:
|
|
1721
|
+
phases.receiptHydrationGateWait.distribution(),
|
|
1722
|
+
receiptCompletionQueue: phases.receiptCompletionQueue.distribution(),
|
|
1723
|
+
receiptCompletionFlight:
|
|
1724
|
+
phases.receiptCompletionFlight.distribution(),
|
|
1725
|
+
receiptCompletionReadBack:
|
|
1726
|
+
phases.receiptCompletionReadBack.distribution(),
|
|
1727
|
+
rowPersistence: phases.rowPersistence.distribution(),
|
|
1728
|
+
dispatchQueueWait: phases.dispatchQueueWait.distribution(),
|
|
1729
|
+
rowResolverGap: phases.rowResolverGap.distribution(),
|
|
1730
|
+
toolCallLogicalWall: phases.toolCallLogicalWall.distribution(),
|
|
1731
|
+
resultDelivery: phases.resultDelivery.distribution(),
|
|
1732
|
+
deliveryWrap: phases.deliveryWrap.distribution(),
|
|
1733
|
+
deliveryPublishWait: phases.deliveryPublishWait.distribution(),
|
|
1734
|
+
deliveryResolve: phases.deliveryResolve.distribution(),
|
|
1735
|
+
flightSerialize: phases.flightSerialize.distribution(),
|
|
1736
|
+
flightTransport: phases.flightTransport.distribution(),
|
|
1737
|
+
flightDecode: phases.flightDecode.distribution(),
|
|
1738
|
+
gatewayAuthLaunch: phases.gatewayAuthLaunch.distribution(),
|
|
1739
|
+
gatewayAuthVerify: phases.gatewayAuthVerify.distribution(),
|
|
1740
|
+
gatewayBodyParse: phases.gatewayBodyParse.distribution(),
|
|
1741
|
+
gatewayBodyInflate: phases.gatewayBodyInflate.distribution(),
|
|
1742
|
+
gatewayPoolWait: phases.gatewayPoolWait.distribution(),
|
|
1743
|
+
gatewayReceiptValuePersist:
|
|
1744
|
+
phases.gatewayReceiptValuePersist.distribution(),
|
|
1745
|
+
gatewayCallback: phases.gatewayCallback.distribution(),
|
|
1746
|
+
gatewayRoundTrip: phases.gatewayRoundTrip.distribution(),
|
|
1747
|
+
gatewayRequestSerialize:
|
|
1748
|
+
phases.gatewayRequestSerialize.distribution(),
|
|
1749
|
+
gatewayRequestPack: phases.gatewayRequestPack.distribution(),
|
|
1750
|
+
},
|
|
1751
|
+
gateway: {
|
|
1752
|
+
authSession: { ...gatewayAuthSessionCounters },
|
|
1753
|
+
requestBody: { ...gatewayRequestBodyCounters },
|
|
1754
|
+
},
|
|
264
1755
|
rows: {
|
|
265
1756
|
acquired: rowCounters.acquired,
|
|
266
1757
|
estimatedBytes: rowCounters.estimatedBytes,
|
|
@@ -275,10 +1766,43 @@ export function createRuntimeResourceGovernor(input: {
|
|
|
275
1766
|
bytes: sheetFlushCounters.bytes,
|
|
276
1767
|
latencyMsEwma: sheetFlushLatency.value,
|
|
277
1768
|
},
|
|
1769
|
+
resultEgress: resultEgressCounters,
|
|
1770
|
+
concurrencyShed: {
|
|
1771
|
+
count: concurrencyShedCounters.count,
|
|
1772
|
+
delayMsEwma: concurrencyShedDelay.value,
|
|
1773
|
+
},
|
|
278
1774
|
providers: Object.fromEntries(
|
|
279
1775
|
[...providers.entries()].map(([key, stats]) => [
|
|
280
1776
|
key,
|
|
281
1777
|
{
|
|
1778
|
+
admission: stats.admission.snapshot(),
|
|
1779
|
+
residence: stats.residence.snapshot(),
|
|
1780
|
+
fetchToHeaders: stats.fetchToHeaders.snapshot(),
|
|
1781
|
+
latencyMsEwma: stats.latency.value,
|
|
1782
|
+
retryAfterMsEwma: stats.retryAfter.value,
|
|
1783
|
+
provider429Count: stats.provider429Count,
|
|
1784
|
+
},
|
|
1785
|
+
]),
|
|
1786
|
+
),
|
|
1787
|
+
providerAttribution: Object.fromEntries(
|
|
1788
|
+
[...providerAttribution.entries()].map(([key, stats]) => [
|
|
1789
|
+
key,
|
|
1790
|
+
{
|
|
1791
|
+
admission: stats.admission.snapshot(),
|
|
1792
|
+
residence: stats.residence.snapshot(),
|
|
1793
|
+
fixtureDelay: stats.fixtureDelay.snapshot(),
|
|
1794
|
+
transportSlotWait: stats.transportSlotWait.snapshot(),
|
|
1795
|
+
fetchToHeaders: stats.fetchToHeaders.snapshot(),
|
|
1796
|
+
bodyRead: stats.bodyRead.snapshot(),
|
|
1797
|
+
gateMs: stats.bodyAdmissionWait.snapshot().totalMs,
|
|
1798
|
+
controller: {
|
|
1799
|
+
permits: stats.controllerPermits,
|
|
1800
|
+
inFlightAtPermit: stats.inFlightAtPermit.snapshot(),
|
|
1801
|
+
runInFlightAtDispatch: stats.runInFlightAtDispatch.snapshot(),
|
|
1802
|
+
targetRequestsPerSecondEwma:
|
|
1803
|
+
stats.targetRequestsPerSecond.value,
|
|
1804
|
+
minimumRttMsEwma: stats.minimumRttMs.value,
|
|
1805
|
+
},
|
|
282
1806
|
latencyMsEwma: stats.latency.value,
|
|
283
1807
|
retryAfterMsEwma: stats.retryAfter.value,
|
|
284
1808
|
provider429Count: stats.provider429Count,
|