deepline 0.3.316 → 0.3.318
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/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +64 -0
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +25 -18
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +284 -26
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +123 -19
- package/dist/cli/{auth-JP7ZJ4OI.mjs → auth-S3C6DGZK.mjs} +4 -4
- package/dist/cli/auth-SPCCVKWR.js +31 -0
- package/dist/cli/{billing-KG6MC2BC.mjs → billing-2YFLKRPB.mjs} +4 -4
- package/dist/cli/{billing-WZGS32ME.js → billing-5RIRFKFK.js} +70 -70
- package/dist/cli/{chunk-46ZOD4PQ.mjs → chunk-43B4IQDT.mjs} +1 -1
- package/dist/cli/{chunk-SRUWVQ66.js → chunk-5KVYDOH3.js} +6 -6
- package/dist/cli/{chunk-K3BIRBT3.js → chunk-6BA2TLYP.js} +6 -6
- package/dist/cli/{chunk-VC25WFXV.mjs → chunk-7SMAPT4Q.mjs} +2 -2
- package/dist/cli/{chunk-GHLWDXUB.js → chunk-A4RINW7O.js} +6 -6
- package/dist/cli/{chunk-BOKHMPCZ.js → chunk-B3K7KANZ.js} +48 -48
- package/dist/cli/{chunk-ZNHGAWYI.js → chunk-GP5PLKPM.js} +2 -2
- package/dist/cli/{chunk-YNSAVFWL.mjs → chunk-GSGCLSB5.mjs} +5 -5
- package/dist/cli/{chunk-MCPHK7AF.js → chunk-H5JENUSW.js} +4 -4
- package/dist/cli/{chunk-J3ZPMADG.mjs → chunk-HDXBDRID.mjs} +1 -1
- package/dist/cli/{chunk-AXAPMVUC.mjs → chunk-HFYYLEXX.mjs} +4 -4
- package/dist/cli/{chunk-IDSDRGKF.mjs → chunk-HNGEUEUZ.mjs} +1 -1
- package/dist/cli/{chunk-D3NMIACS.mjs → chunk-N6SHI2NI.mjs} +1 -1
- package/dist/cli/{chunk-F2T5UENG.mjs → chunk-OQOCU7N2.mjs} +1 -1
- package/dist/cli/{chunk-OB3SYJGU.mjs → chunk-OUWH3UQI.mjs} +3 -3
- package/dist/cli/{chunk-TYSAKSX7.mjs → chunk-PBW4AMCS.mjs} +2 -2
- package/dist/cli/{chunk-C6QGM72M.js → chunk-QIDESZOK.js} +1 -1
- package/dist/cli/{chunk-PJERS5VW.js → chunk-SPPR7IUB.js} +6 -6
- package/dist/cli/{chunk-G2G67D3L.js → chunk-T4D5DSN2.js} +60 -60
- package/dist/cli/{chunk-35YXDTOB.js → chunk-TXWPV43B.js} +26 -26
- package/dist/cli/{chunk-6R5ACEWN.mjs → chunk-UIYTVYVJ.mjs} +6 -6
- package/dist/cli/{chunk-B6OOVO3A.js → chunk-UVEB46UN.js} +220 -220
- package/dist/cli/{chunk-YEMOOWZI.js → chunk-VQFYTD3E.js} +50 -50
- package/dist/cli/{chunk-RBBSRB56.js → chunk-WCR65D2N.js} +15 -15
- package/dist/cli/{chunk-VDPBQCRQ.mjs → chunk-XXNE65K5.mjs} +2 -2
- package/dist/cli/{chunk-DAFGPNVW.mjs → chunk-YNIUFZ5B.mjs} +1 -1
- package/dist/cli/{client-MNPM4ME3.mjs → client-BMLSQMUI.mjs} +3 -3
- package/dist/cli/client-LSNRA76T.js +20 -0
- package/dist/cli/{csv-ZME7HAPR.mjs → csv-RNUTR7LO.mjs} +3 -3
- package/dist/cli/{csv-G72FIQWI.js → csv-YQXSHIVH.js} +12 -12
- package/dist/cli/{db-KRBWHSMA.js → db-ABWJP4XY.js} +20 -20
- package/dist/cli/{db-K2DS4PEY.mjs → db-DOZJ35SZ.mjs} +4 -4
- package/dist/cli/{describe-LXBJP6OP.mjs → describe-JMUJC7S6.mjs} +8 -8
- package/dist/cli/{describe-UKFV376D.js → describe-JRWDWFIN.js} +15 -15
- package/dist/cli/{executions-2V3AROY6.mjs → executions-KF7WZKF4.mjs} +4 -4
- package/dist/cli/{executions-E66AM4JU.js → executions-WOQ3HYRQ.js} +6 -6
- package/dist/cli/{feedback-7C2N7M37.js → feedback-6ZPHQNTY.js} +6 -6
- package/dist/cli/{feedback-IEPZ2XKZ.mjs → feedback-KLO5S6CV.mjs} +3 -3
- package/dist/cli/git-2VCXV5SK.js +23 -0
- package/dist/cli/{git-AR5KGN4O.mjs → git-4AQH6JOC.mjs} +4 -4
- package/dist/cli/index.js +75 -75
- package/dist/cli/index.mjs +31 -31
- package/dist/cli/{legacy-noops-A2SH45P4.js → legacy-noops-PFCAMJ5O.js} +7 -7
- package/dist/cli/{legacy-noops-LC2EGAZU.mjs → legacy-noops-WJL3CCKD.mjs} +4 -4
- package/dist/cli/{monitors-5YPW3IZQ.mjs → monitors-RYTEFDAX.mjs} +4 -4
- package/dist/cli/{monitors-IZBUPKPW.js → monitors-RYZ6RQWJ.js} +85 -85
- package/dist/cli/{org-L42SQ65U.js → org-PZNEI4Z2.js} +60 -60
- package/dist/cli/{org-2OMYI5KJ.mjs → org-TUITFKO6.mjs} +4 -4
- package/dist/cli/play-PQ2PS5WY.js +152 -0
- package/dist/cli/{play-UPCBLAOH.mjs → play-STV34EKC.mjs} +7 -7
- package/dist/cli/{providers-VE2RM56M.mjs → providers-G374UPE3.mjs} +4 -4
- package/dist/cli/{providers-GGNDWUKB.js → providers-K2TDVWWY.js} +7 -7
- package/dist/cli/{quickstart-4CZHURUX.js → quickstart-QI6Z5VU2.js} +5 -5
- package/dist/cli/{quickstart-HSJ7FU7Z.mjs → quickstart-RBKEB32U.mjs} +3 -3
- package/dist/cli/search-3FQ6SCDN.js +26 -0
- package/dist/cli/{search-MWBM3I2L.mjs → search-VIVNNMFH.mjs} +5 -5
- package/dist/cli/{secrets-W5DQYKGU.mjs → secrets-FPD6A32B.mjs} +4 -4
- package/dist/cli/{secrets-CWBPGDZV.js → secrets-GXFMHRUN.js} +13 -13
- package/dist/cli/{sessions-Q42GUYTF.mjs → sessions-7XXZRPIR.mjs} +4 -4
- package/dist/cli/{sessions-EDCFU6P2.js → sessions-HQLIG25E.js} +5 -5
- package/dist/cli/{settings-SO56AJPQ.mjs → settings-C24HFGVP.mjs} +7 -7
- package/dist/cli/{settings-OKRENZGX.js → settings-J72DQVQO.js} +74 -74
- package/dist/cli/{setup-7PLHLNLS.js → setup-AM4MIXQJ.js} +41 -41
- package/dist/cli/{setup-OTYMF5CZ.mjs → setup-Z76VRJ3C.mjs} +6 -6
- package/dist/cli/{skills-4UFS4FXP.mjs → skills-2MNX5O4X.mjs} +4 -4
- package/dist/cli/skills-6Z2V3HBJ.js +28 -0
- package/dist/cli/{tools-6FV543YV.mjs → tools-GZIJWL36.mjs} +6 -6
- package/dist/cli/tools-XC2O6EHT.js +38 -0
- package/dist/cli/update-D4NV3VSL.js +28 -0
- package/dist/cli/{update-6POGDXYW.mjs → update-DDJS3QNN.mjs} +6 -6
- package/dist/cli/{workflow-RB4POZP5.js → workflow-2WDLLVYG.js} +15 -15
- package/dist/cli/{workflow-HVZSFWYR.mjs → workflow-DYC6Q4BG.mjs} +5 -5
- package/dist/index.js +6 -6
- package/dist/index.mjs +3 -3
- package/dist/install-integrity.json +74 -74
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +2 -2
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
- package/dist/cli/auth-SPUJ4EXC.js +0 -31
- package/dist/cli/client-GMMPQT7B.js +0 -20
- package/dist/cli/git-EXYB66IH.js +0 -23
- package/dist/cli/play-CQI3IDDN.js +0 -152
- package/dist/cli/search-PD5FBCUN.js +0 -26
- package/dist/cli/skills-IP7IW7EQ.js +0 -28
- package/dist/cli/tools-A2YNR6PI.js +0 -38
- package/dist/cli/update-QXSGKLJG.js +0 -28
|
@@ -200,7 +200,7 @@ export const SDK_RELEASE = {
|
|
|
200
200
|
// getters keep their established compatibility behavior.
|
|
201
201
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
202
202
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
203
|
-
version: '0.3.
|
|
203
|
+
version: '0.3.318',
|
|
204
204
|
updateSummary:
|
|
205
205
|
'Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.',
|
|
206
206
|
packageCapabilities: {
|
|
@@ -385,9 +385,24 @@ export type WorkerRuntimeApiContext = {
|
|
|
385
385
|
* gateway record that produced it.
|
|
386
386
|
*/
|
|
387
387
|
onResponseMeta?: (meta: RuntimeApiResponseMeta) => void;
|
|
388
|
+
/**
|
|
389
|
+
* Observe each request attempt as it is sent. `onResponseMeta` only fires
|
|
390
|
+
* for a successful response, so an attempt that is aborted or times out
|
|
391
|
+
* names nothing there; this carries the per-attempt id that the request
|
|
392
|
+
* already sends in its transport-attempt header, which a receiver can log.
|
|
393
|
+
* Diagnostic only: log it, never persist it on a run, status, or receipt
|
|
394
|
+
* document.
|
|
395
|
+
*/
|
|
396
|
+
onRequestAttempt?: (attempt: RuntimeApiRequestAttempt) => void;
|
|
388
397
|
signal?: AbortSignal;
|
|
389
398
|
};
|
|
390
399
|
|
|
400
|
+
export type RuntimeApiRequestAttempt = {
|
|
401
|
+
action: RuntimeApiRequest['action'];
|
|
402
|
+
/** The value of this attempt's transport-attempt request header. */
|
|
403
|
+
transportAttemptId: string;
|
|
404
|
+
};
|
|
405
|
+
|
|
391
406
|
/**
|
|
392
407
|
* The receipt gateway's own account of a request, from its `Server-Timing`
|
|
393
408
|
* response header. Its `runtime.gateway.action.finished` durationMs starts
|
|
@@ -423,6 +438,19 @@ export type RuntimeApiResponseMeta = {
|
|
|
423
438
|
roundTripMs?: number | null;
|
|
424
439
|
/** Absent when the gateway sent no `Server-Timing` header. */
|
|
425
440
|
serverTiming?: RuntimeGatewayServerTiming | null;
|
|
441
|
+
/**
|
|
442
|
+
* The hosting platform's id for the responding request (`x-vercel-id`), so a
|
|
443
|
+
* slow app-runtime hop can be matched to its platform request log. Null when
|
|
444
|
+
* the receiver is not fronted by one. Diagnostic only: log it, never persist
|
|
445
|
+
* it on a run, status, or receipt document.
|
|
446
|
+
*/
|
|
447
|
+
platformRequestId?: string | null;
|
|
448
|
+
/**
|
|
449
|
+
* The raw `Server-Timing` header, truncated. App routes name their own
|
|
450
|
+
* entries, which `serverTiming` (the gateway's schema) does not parse.
|
|
451
|
+
* Diagnostic only, under the same rule as `platformRequestId`.
|
|
452
|
+
*/
|
|
453
|
+
serverTimingHeader?: string | null;
|
|
426
454
|
/**
|
|
427
455
|
* Serialized JSON bytes of the request body, before compression. Set on
|
|
428
456
|
* every request, so `wire / raw` across a run is the compression ratio the
|
|
@@ -447,6 +475,27 @@ export type RuntimeApiResponseMeta = {
|
|
|
447
475
|
requestBodyPackMs?: number | null;
|
|
448
476
|
};
|
|
449
477
|
|
|
478
|
+
const RUNTIME_API_DIAGNOSTIC_HEADER_MAX_CHARS = 256;
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Read one response header for a log line: trimmed, bounded, and total. A
|
|
482
|
+
* receiver controls this value, so it is capped before it reaches a record.
|
|
483
|
+
*/
|
|
484
|
+
export function readRuntimeApiDiagnosticHeader(
|
|
485
|
+
headers: Pick<Headers, 'get'> | null | undefined,
|
|
486
|
+
name: string,
|
|
487
|
+
): string | null {
|
|
488
|
+
try {
|
|
489
|
+
const value = headers?.get(name)?.trim();
|
|
490
|
+
return value
|
|
491
|
+
? value.slice(0, RUNTIME_API_DIAGNOSTIC_HEADER_MAX_CHARS)
|
|
492
|
+
: null;
|
|
493
|
+
} catch {
|
|
494
|
+
// Observation must never affect durable delivery.
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
450
499
|
const RUNTIME_GATEWAY_AUTH_SESSION_VALUES = new Set([
|
|
451
500
|
'hit',
|
|
452
501
|
'miss',
|
|
@@ -1519,6 +1568,13 @@ async function postAppRuntimeApi<TResponse>(
|
|
|
1519
1568
|
// would show up as network cost that no round trip explains.
|
|
1520
1569
|
const attemptStartedAt = Date.now();
|
|
1521
1570
|
const transportAttemptId = randomUUID();
|
|
1571
|
+
if (context.onRequestAttempt) {
|
|
1572
|
+
try {
|
|
1573
|
+
context.onRequestAttempt({ action: body.action, transportAttemptId });
|
|
1574
|
+
} catch {
|
|
1575
|
+
// Observation must never affect durable delivery.
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1522
1578
|
const requestSignal = context.signal
|
|
1523
1579
|
? AbortSignal.any([context.signal, AbortSignal.timeout(requestTimeoutMs)])
|
|
1524
1580
|
: AbortSignal.timeout(requestTimeoutMs);
|
|
@@ -1680,6 +1736,14 @@ async function postAppRuntimeApi<TResponse>(
|
|
|
1680
1736
|
serverTiming: parseRuntimeGatewayServerTiming(
|
|
1681
1737
|
response.headers.get('server-timing'),
|
|
1682
1738
|
),
|
|
1739
|
+
platformRequestId: readRuntimeApiDiagnosticHeader(
|
|
1740
|
+
response.headers,
|
|
1741
|
+
'x-vercel-id',
|
|
1742
|
+
),
|
|
1743
|
+
serverTimingHeader: readRuntimeApiDiagnosticHeader(
|
|
1744
|
+
response.headers,
|
|
1745
|
+
'server-timing',
|
|
1746
|
+
),
|
|
1683
1747
|
requestBodyRawBytes: wireBody.rawBytes,
|
|
1684
1748
|
requestBodyWireBytes: wireBody.wireBytes,
|
|
1685
1749
|
requestBodySerializeMs,
|
|
@@ -1302,36 +1302,43 @@ function terminalFailureSummary(
|
|
|
1302
1302
|
export function ledgerTerminalResultRefForValue(
|
|
1303
1303
|
value: unknown,
|
|
1304
1304
|
reason: LedgerTerminalResultRefReason,
|
|
1305
|
-
options: { content?: 'full' } = {},
|
|
1305
|
+
options: { content?: 'full'; deriveMetadata?: boolean } = {},
|
|
1306
1306
|
): LedgerTerminalResultRef {
|
|
1307
|
+
// Fallbacks after a rejected projection must not serialize the same payload
|
|
1308
|
+
// again just to derive optional metadata.
|
|
1309
|
+
const { content, deriveMetadata = true } = options;
|
|
1307
1310
|
let bytes: number | undefined;
|
|
1308
|
-
try {
|
|
1309
|
-
bytes = jsonByteLengthUpTo(value, LEDGER_TERMINAL_RESULT_MAX_BYTES).bytes;
|
|
1310
|
-
} catch {
|
|
1311
|
-
// The bounded reason is the useful diagnostic. Never serialize the
|
|
1312
|
-
// customer payload again merely to populate reference metadata.
|
|
1313
|
-
}
|
|
1314
1311
|
let preview: BoundedRunListOutputPreview | undefined;
|
|
1315
1312
|
let responsePreview: LedgerStoredRunOutputPreview | undefined;
|
|
1316
|
-
|
|
1313
|
+
let failure: LedgerTerminalFailureSummary | undefined;
|
|
1314
|
+
if (deriveMetadata) {
|
|
1317
1315
|
try {
|
|
1318
|
-
|
|
1319
|
-
responsePreview = reuseRunListValuesInOutputPreview(
|
|
1320
|
-
buildBoundedRunOutputPreview(value),
|
|
1321
|
-
preview,
|
|
1322
|
-
);
|
|
1316
|
+
bytes = jsonByteLengthUpTo(value, LEDGER_TERMINAL_RESULT_MAX_BYTES).bytes;
|
|
1323
1317
|
} catch {
|
|
1324
|
-
// The
|
|
1325
|
-
//
|
|
1326
|
-
|
|
1318
|
+
// The bounded reason is the useful diagnostic. Never serialize the
|
|
1319
|
+
// customer payload again merely to populate reference metadata.
|
|
1320
|
+
}
|
|
1321
|
+
if (content && isPlainObject(value)) {
|
|
1322
|
+
try {
|
|
1323
|
+
preview = buildBoundedRunListOutputPreview(value);
|
|
1324
|
+
responsePreview = reuseRunListValuesInOutputPreview(
|
|
1325
|
+
buildBoundedRunOutputPreview(value),
|
|
1326
|
+
preview,
|
|
1327
|
+
);
|
|
1328
|
+
} catch {
|
|
1329
|
+
// The terminal reference is the durable fallback. A hostile/non-JSON
|
|
1330
|
+
// value must not turn optional list-preview derivation into a terminal
|
|
1331
|
+
// persistence failure.
|
|
1332
|
+
}
|
|
1327
1333
|
}
|
|
1334
|
+
failure = terminalFailureSummary(value);
|
|
1328
1335
|
}
|
|
1329
1336
|
return ledgerTerminalResultRef(reason, {
|
|
1330
|
-
...
|
|
1337
|
+
...(content ? { content } : {}),
|
|
1331
1338
|
bytes,
|
|
1332
1339
|
preview,
|
|
1333
1340
|
responsePreview,
|
|
1334
|
-
failure
|
|
1341
|
+
failure,
|
|
1335
1342
|
});
|
|
1336
1343
|
}
|
|
1337
1344
|
|
|
@@ -161,7 +161,10 @@ import {
|
|
|
161
161
|
loadArtifactFromAppRuntime,
|
|
162
162
|
loadStagedFileFromAppRuntime,
|
|
163
163
|
projectRunCreatedViaAppRuntime,
|
|
164
|
+
readRuntimeApiDiagnosticHeader,
|
|
164
165
|
startRunViaAppRuntime,
|
|
166
|
+
type RuntimeApiRequestAttempt,
|
|
167
|
+
type RuntimeApiResponseMeta,
|
|
165
168
|
type StoredPlayArtifactPayload,
|
|
166
169
|
type WorkerRuntimeApiContext,
|
|
167
170
|
} from '../app-runtime-api';
|
|
@@ -19723,6 +19726,14 @@ export type RunLedgerOutboxDispatchInput = {
|
|
|
19723
19726
|
* can take the same row immediately under the same idempotency key.
|
|
19724
19727
|
*/
|
|
19725
19728
|
signal?: AbortSignal;
|
|
19729
|
+
/**
|
|
19730
|
+
* Told once when an attempt abandoned by `signal` has handed back the lease
|
|
19731
|
+
* it took: `true` when the owner-fenced release statement completed (a
|
|
19732
|
+
* release that matched no row counts, since nothing is then held), `false`
|
|
19733
|
+
* when it could not run and the lease is left to expire. Not called when
|
|
19734
|
+
* the attempt never took a lease. Never affects delivery.
|
|
19735
|
+
*/
|
|
19736
|
+
onAbortedLeaseRelease?: (released: boolean) => void;
|
|
19726
19737
|
/**
|
|
19727
19738
|
* Observation hook for acknowledged rows (event type and commit-to-ack lag
|
|
19728
19739
|
* measured on the database clock). Never affects delivery.
|
|
@@ -20079,7 +20090,45 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
20079
20090
|
});
|
|
20080
20091
|
}
|
|
20081
20092
|
};
|
|
20093
|
+
// The claim can be invoked more than once for one dispatch: the pool
|
|
20094
|
+
// re-runs a checkout's operation after a connection failure, and the claim
|
|
20095
|
+
// itself is retried once on the missing-marker compatibility path.
|
|
20096
|
+
let claimInvocations = 0;
|
|
20097
|
+
// An abandoned attempt that already handed its lease back on a checkout it
|
|
20098
|
+
// held does not spend another checkout on the same release.
|
|
20099
|
+
const abandonedLease = { released: false };
|
|
20082
20100
|
const claimEvents = async (client: PostgresSchedulerQueryClient) => {
|
|
20101
|
+
claimInvocations += 1;
|
|
20102
|
+
const abandonedHeadEventId = input.headEventId?.trim();
|
|
20103
|
+
if (
|
|
20104
|
+
input.signal?.aborted &&
|
|
20105
|
+
(claimInvocations === 1 || abandonedHeadEventId)
|
|
20106
|
+
) {
|
|
20107
|
+
// The caller's deadline elapsed while this checkout was queued. Its
|
|
20108
|
+
// attempt is already abandoned, so taking a lease now could only keep
|
|
20109
|
+
// the durable projector off the row until that lease expires. Claim
|
|
20110
|
+
// nothing: the row stays pending and unleased for its next owner.
|
|
20111
|
+
if (claimInvocations > 1 && abandonedHeadEventId) {
|
|
20112
|
+
// An earlier invocation's COMMIT may have reached the server before
|
|
20113
|
+
// its connection failed, so this owner can already hold the named
|
|
20114
|
+
// head. Hand it back here, fenced to this owner; returning empty
|
|
20115
|
+
// would leave that lease with nobody to release it. After a rolled
|
|
20116
|
+
// back invocation it matches no row. A failure propagates, so the
|
|
20117
|
+
// attempt is never reported as settled.
|
|
20118
|
+
await releasePostgresSchedulerOutboxLease(
|
|
20119
|
+
client,
|
|
20120
|
+
[abandonedHeadEventId],
|
|
20121
|
+
{ ...options, leaseOwner },
|
|
20122
|
+
);
|
|
20123
|
+
}
|
|
20124
|
+
const unclaimed: {
|
|
20125
|
+
events: PostgresSchedulerOutboxEvent[];
|
|
20126
|
+
launchJson: unknown;
|
|
20127
|
+
} = { events: [], launchJson: undefined };
|
|
20128
|
+
return unclaimed;
|
|
20129
|
+
}
|
|
20130
|
+
// A re-invocation with no named head claims again under the same owner,
|
|
20131
|
+
// as it always has; the abort check after the claim releases by id.
|
|
20083
20132
|
// The checkout is exclusive. Hold the existing scheduler run's row lock
|
|
20084
20133
|
// only while choosing/claiming its outbox prefix, never over HTTP. A
|
|
20085
20134
|
// second statement takes a fresh READ COMMITTED snapshot after the lock:
|
|
@@ -20274,6 +20323,26 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
20274
20323
|
let authorityReadyAtMs: number | null = null;
|
|
20275
20324
|
let appendFinishedAtMs: number | null = null;
|
|
20276
20325
|
let acknowledgedAtMs: number | null = null;
|
|
20326
|
+
// How this delivery obtained its app authority, for the slow-delivery
|
|
20327
|
+
// record only. `token` is set only when the dispatch-token endpoint was
|
|
20328
|
+
// actually consulted; a token pre-minted at admission and an authority
|
|
20329
|
+
// reused within the drain make no such request.
|
|
20330
|
+
const authorityObserved: {
|
|
20331
|
+
token: RunLedgerDispatchTokenObservation | null;
|
|
20332
|
+
reusedWithinDrain: boolean;
|
|
20333
|
+
} = { token: null, reusedWithinDrain: false };
|
|
20334
|
+
// Platform identity of the slowest append response, for the same record.
|
|
20335
|
+
// Null when no append was answered or its receiver sent no such header.
|
|
20336
|
+
let appendResponse:
|
|
20337
|
+
| (RunLedgerDispatchResponseTrace & { roundTripMs: number | null })
|
|
20338
|
+
| null = null;
|
|
20339
|
+
const callerOnResponseMeta = input.runtimeApi?.onResponseMeta;
|
|
20340
|
+
// The last append attempt sent, named even when it never gets a response
|
|
20341
|
+
// (an append aborted at the caller's deadline has no response to read).
|
|
20342
|
+
const appendAttempt: { transportAttemptId: string | null } = {
|
|
20343
|
+
transportAttemptId: null,
|
|
20344
|
+
};
|
|
20345
|
+
const callerOnRequestAttempt = input.runtimeApi?.onRequestAttempt;
|
|
20277
20346
|
const materializeDeferredObservability = async () => {
|
|
20278
20347
|
if (
|
|
20279
20348
|
events.some(
|
|
@@ -20401,6 +20470,10 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
20401
20470
|
return null;
|
|
20402
20471
|
};
|
|
20403
20472
|
try {
|
|
20473
|
+
// A deadline that elapsed during the claim abandons the attempt before
|
|
20474
|
+
// any authority or renewal work. The abort branch below hands the lease
|
|
20475
|
+
// straight back without charging a projection attempt.
|
|
20476
|
+
input.signal?.throwIfAborted();
|
|
20404
20477
|
// The ledger converter rejects raw deferred facts. Inline callers hand
|
|
20405
20478
|
// them off; the background owner projects them before inspecting the
|
|
20406
20479
|
// compact lifecycle payload or deciding that it needs no HTTP append.
|
|
@@ -20472,6 +20545,11 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
20472
20545
|
),
|
|
20473
20546
|
) + RUNTIME_RELIABILITY_POLICY.schedulerDatabase.queryTimeoutMs;
|
|
20474
20547
|
const cachedAuthority = authorityScope.authority;
|
|
20548
|
+
const observeDispatchTokenResponse = (
|
|
20549
|
+
observation: RunLedgerDispatchTokenObservation,
|
|
20550
|
+
) => {
|
|
20551
|
+
authorityObserved.token = observation;
|
|
20552
|
+
};
|
|
20475
20553
|
const resolveRunRuntimeApi = () =>
|
|
20476
20554
|
launchJson !== null
|
|
20477
20555
|
? resolvePostgresSchedulerRuntimeApiForRun(
|
|
@@ -20484,6 +20562,7 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
20484
20562
|
options,
|
|
20485
20563
|
input.runtimeApi?.signal,
|
|
20486
20564
|
reuseMarginMs,
|
|
20565
|
+
observeDispatchTokenResponse,
|
|
20487
20566
|
)
|
|
20488
20567
|
: loadPostgresSchedulerRuntimeApiForRun(
|
|
20489
20568
|
withClient,
|
|
@@ -20495,6 +20574,7 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
20495
20574
|
options,
|
|
20496
20575
|
input.runtimeApi?.signal,
|
|
20497
20576
|
reuseMarginMs,
|
|
20577
|
+
observeDispatchTokenResponse,
|
|
20498
20578
|
);
|
|
20499
20579
|
const gatewayRuntimeApi =
|
|
20500
20580
|
needsRuntimeApi && tokenAuthority === 'gateway'
|
|
@@ -20505,6 +20585,11 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
20505
20585
|
? cachedAuthority.runtimeApi
|
|
20506
20586
|
: await resolveRunRuntimeApi()
|
|
20507
20587
|
: null;
|
|
20588
|
+
// Read-only: an authority carried over from an earlier prefix of this
|
|
20589
|
+
// drain made no request for this delivery.
|
|
20590
|
+
authorityObserved.reusedWithinDrain =
|
|
20591
|
+
gatewayRuntimeApi !== null &&
|
|
20592
|
+
gatewayRuntimeApi === cachedAuthority?.runtimeApi;
|
|
20508
20593
|
if (
|
|
20509
20594
|
gatewayRuntimeApi &&
|
|
20510
20595
|
cachedAuthority?.runId === first.runId &&
|
|
@@ -20542,6 +20627,27 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
20542
20627
|
: {}),
|
|
20543
20628
|
}
|
|
20544
20629
|
: {}),
|
|
20630
|
+
// Keep the slowest append response's platform identity for the
|
|
20631
|
+
// slow-delivery record, then hand the caller's own observer the same
|
|
20632
|
+
// meta it always received. Observation never affects delivery.
|
|
20633
|
+
onResponseMeta: (meta: RuntimeApiResponseMeta) => {
|
|
20634
|
+
const roundTripMs = meta.roundTripMs ?? null;
|
|
20635
|
+
if (
|
|
20636
|
+
appendResponse === null ||
|
|
20637
|
+
(roundTripMs ?? 0) >= (appendResponse.roundTripMs ?? 0)
|
|
20638
|
+
) {
|
|
20639
|
+
appendResponse = {
|
|
20640
|
+
platformRequestId: meta.platformRequestId ?? null,
|
|
20641
|
+
serverTimingHeader: meta.serverTimingHeader ?? null,
|
|
20642
|
+
roundTripMs,
|
|
20643
|
+
};
|
|
20644
|
+
}
|
|
20645
|
+
callerOnResponseMeta?.(meta);
|
|
20646
|
+
},
|
|
20647
|
+
onRequestAttempt: (attempt: RuntimeApiRequestAttempt) => {
|
|
20648
|
+
appendAttempt.transportAttemptId = attempt.transportAttemptId;
|
|
20649
|
+
callerOnRequestAttempt?.(attempt);
|
|
20650
|
+
},
|
|
20545
20651
|
retryPolicy: 'none' as const,
|
|
20546
20652
|
// The caller-owned admission deadline (see `signal` above) wins.
|
|
20547
20653
|
...(input.signal ? { signal: input.signal } : {}),
|
|
@@ -20669,11 +20775,22 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
20669
20775
|
expiresAtMs: runtimeApiTokenExpiresAtMs(runtimeApi.executorToken),
|
|
20670
20776
|
};
|
|
20671
20777
|
}
|
|
20672
|
-
await withClient((client) =>
|
|
20673
|
-
|
|
20778
|
+
const renewed = await withClient(async (client) => {
|
|
20779
|
+
const eventIds = events.map((event) => event.eventId);
|
|
20780
|
+
if (input.signal?.aborted) {
|
|
20781
|
+
// The caller's deadline elapsed while this checkout was queued.
|
|
20782
|
+
// Renewing now would extend an abandoned attempt's lease by a full
|
|
20783
|
+
// term. Hand it back on this same checkout instead.
|
|
20784
|
+
await releasePostgresSchedulerOutboxLease(client, eventIds, {
|
|
20785
|
+
...options,
|
|
20786
|
+
leaseOwner,
|
|
20787
|
+
});
|
|
20788
|
+
return false;
|
|
20789
|
+
}
|
|
20790
|
+
await renewPostgresRunLedgerDelivery(
|
|
20674
20791
|
client,
|
|
20675
20792
|
{
|
|
20676
|
-
eventIds
|
|
20793
|
+
eventIds,
|
|
20677
20794
|
leaseOwner,
|
|
20678
20795
|
leaseSeconds: input.leaseSeconds ?? 120,
|
|
20679
20796
|
freezeReceipt:
|
|
@@ -20684,8 +20801,14 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
20684
20801
|
),
|
|
20685
20802
|
},
|
|
20686
20803
|
options,
|
|
20687
|
-
)
|
|
20688
|
-
|
|
20804
|
+
);
|
|
20805
|
+
return true;
|
|
20806
|
+
});
|
|
20807
|
+
if (!renewed) {
|
|
20808
|
+
abandonedLease.released = true;
|
|
20809
|
+
// Stop before the append; the abort branch below reports the outcome.
|
|
20810
|
+
input.signal?.throwIfAborted();
|
|
20811
|
+
}
|
|
20689
20812
|
};
|
|
20690
20813
|
if (needsRuntimeApi && runtimeApi) {
|
|
20691
20814
|
const append = async (runtimeApi: WorkerRuntimeApiContext) => {
|
|
@@ -20832,28 +20955,41 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
20832
20955
|
// replay carries the same idempotency key and is a no-op there.
|
|
20833
20956
|
const eventIds = events.map((event) => event.eventId);
|
|
20834
20957
|
let released: string[];
|
|
20835
|
-
|
|
20836
|
-
|
|
20837
|
-
|
|
20838
|
-
releasePostgresSchedulerOutboxLease(client, eventIds, {
|
|
20839
|
-
...options,
|
|
20840
|
-
leaseOwner,
|
|
20841
|
-
}),
|
|
20842
|
-
{
|
|
20843
|
-
runId: events[0]!.runId,
|
|
20844
|
-
phase: 'run_ledger_outbox_lease_release',
|
|
20845
|
-
priority: 'critical',
|
|
20846
|
-
},
|
|
20847
|
-
);
|
|
20848
|
-
} catch (settlementError) {
|
|
20849
|
-
logRunLedgerOutboxSettlementFailure({
|
|
20850
|
-
runId: events[0]!.runId,
|
|
20851
|
-
eventIds,
|
|
20852
|
-
stage: 'aborted_release',
|
|
20853
|
-
settlementError,
|
|
20854
|
-
deliveryError: error,
|
|
20855
|
-
});
|
|
20958
|
+
let releaseLanded = abandonedLease.released;
|
|
20959
|
+
if (releaseLanded) {
|
|
20960
|
+
// The renewal checkout already handed the lease back.
|
|
20856
20961
|
released = eventIds;
|
|
20962
|
+
} else {
|
|
20963
|
+
try {
|
|
20964
|
+
released = await withClient(
|
|
20965
|
+
(client) =>
|
|
20966
|
+
releasePostgresSchedulerOutboxLease(client, eventIds, {
|
|
20967
|
+
...options,
|
|
20968
|
+
leaseOwner,
|
|
20969
|
+
}),
|
|
20970
|
+
{
|
|
20971
|
+
runId: events[0]!.runId,
|
|
20972
|
+
phase: 'run_ledger_outbox_lease_release',
|
|
20973
|
+
priority: 'critical',
|
|
20974
|
+
},
|
|
20975
|
+
);
|
|
20976
|
+
releaseLanded = true;
|
|
20977
|
+
} catch (settlementError) {
|
|
20978
|
+
logRunLedgerOutboxSettlementFailure({
|
|
20979
|
+
runId: events[0]!.runId,
|
|
20980
|
+
eventIds,
|
|
20981
|
+
stage: 'aborted_release',
|
|
20982
|
+
settlementError,
|
|
20983
|
+
deliveryError: error,
|
|
20984
|
+
});
|
|
20985
|
+
released = eventIds;
|
|
20986
|
+
}
|
|
20987
|
+
}
|
|
20988
|
+
try {
|
|
20989
|
+
// The caller must not read a failed release as a settled lease.
|
|
20990
|
+
input.onAbortedLeaseRelease?.(releaseLanded);
|
|
20991
|
+
} catch {
|
|
20992
|
+
// Observation must never affect durable delivery.
|
|
20857
20993
|
}
|
|
20858
20994
|
return {
|
|
20859
20995
|
attempted: events.length,
|
|
@@ -21036,6 +21172,19 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
21036
21172
|
continuationMs:
|
|
21037
21173
|
acknowledgedAtMs === null ? null : settledAtMs - acknowledgedAtMs,
|
|
21038
21174
|
durationMs: settledAtMs - dispatchStartedAtMs,
|
|
21175
|
+
// Which platform requests served the two app hops, so a slow
|
|
21176
|
+
// authority or append stage can be found in the app's request log.
|
|
21177
|
+
...runLedgerSlowDeliveryResponseFields(
|
|
21178
|
+
runLedgerDeliveryAuthoritySource({
|
|
21179
|
+
authorityReady: authorityReadyAtMs !== null,
|
|
21180
|
+
tokenAuthority,
|
|
21181
|
+
reusedWithinDrain: authorityObserved.reusedWithinDrain,
|
|
21182
|
+
token: authorityObserved.token,
|
|
21183
|
+
}),
|
|
21184
|
+
authorityObserved.token?.trace ?? null,
|
|
21185
|
+
appendResponse,
|
|
21186
|
+
appendAttempt.transportAttemptId,
|
|
21187
|
+
),
|
|
21039
21188
|
});
|
|
21040
21189
|
}
|
|
21041
21190
|
}
|
|
@@ -21380,6 +21529,9 @@ async function resolvePostgresSchedulerRuntimeApiForRun(
|
|
|
21380
21529
|
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
21381
21530
|
signal?: AbortSignal,
|
|
21382
21531
|
tokenReuseMarginMs = 0,
|
|
21532
|
+
onDispatchTokenResponse?: (
|
|
21533
|
+
observation: RunLedgerDispatchTokenObservation,
|
|
21534
|
+
) => void,
|
|
21383
21535
|
): Promise<
|
|
21384
21536
|
WorkerRuntimeApiContext & {
|
|
21385
21537
|
refreshExecutorToken?: () => Promise<string>;
|
|
@@ -21441,6 +21593,14 @@ async function resolvePostgresSchedulerRuntimeApiForRun(
|
|
|
21441
21593
|
} else {
|
|
21442
21594
|
const dispatchAuthority =
|
|
21443
21595
|
await requestRunLedgerDispatchToken(dispatchRequest);
|
|
21596
|
+
try {
|
|
21597
|
+
onDispatchTokenResponse?.({
|
|
21598
|
+
reused: dispatchAuthority.reused,
|
|
21599
|
+
trace: dispatchAuthority.responseTrace ?? null,
|
|
21600
|
+
});
|
|
21601
|
+
} catch {
|
|
21602
|
+
// Observation must never affect durable delivery.
|
|
21603
|
+
}
|
|
21444
21604
|
invalidateExecutorToken = () =>
|
|
21445
21605
|
runLedgerDispatchTokens.delete(dispatchAuthority.cacheKey);
|
|
21446
21606
|
if (dispatchAuthority.reused) {
|
|
@@ -21475,6 +21635,9 @@ async function loadPostgresSchedulerRuntimeApiForRun(
|
|
|
21475
21635
|
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
21476
21636
|
signal?: AbortSignal,
|
|
21477
21637
|
tokenReuseMarginMs = 0,
|
|
21638
|
+
onDispatchTokenResponse?: (
|
|
21639
|
+
observation: RunLedgerDispatchTokenObservation,
|
|
21640
|
+
) => void,
|
|
21478
21641
|
): ReturnType<typeof resolvePostgresSchedulerRuntimeApiForRun> {
|
|
21479
21642
|
// A continuation already owns its next event lease, so its launch context
|
|
21480
21643
|
// is not part of the preclaim result. Load only the authority fields here.
|
|
@@ -21495,9 +21658,92 @@ async function loadPostgresSchedulerRuntimeApiForRun(
|
|
|
21495
21658
|
options,
|
|
21496
21659
|
signal,
|
|
21497
21660
|
tokenReuseMarginMs,
|
|
21661
|
+
onDispatchTokenResponse,
|
|
21498
21662
|
);
|
|
21499
21663
|
}
|
|
21500
21664
|
|
|
21665
|
+
/**
|
|
21666
|
+
* Platform identity of one app response on the Run Ledger delivery path
|
|
21667
|
+
* (`x-vercel-id` and the raw `Server-Timing` header, both bounded). It exists
|
|
21668
|
+
* only to label the `[run-ledger-outbox.slow_delivery]` log record. It carries
|
|
21669
|
+
* no credential and no run, org, or customer identifier, and it must never be
|
|
21670
|
+
* written to a run, status, or receipt document.
|
|
21671
|
+
*/
|
|
21672
|
+
type RunLedgerDispatchResponseTrace = {
|
|
21673
|
+
platformRequestId: string | null;
|
|
21674
|
+
serverTimingHeader: string | null;
|
|
21675
|
+
};
|
|
21676
|
+
|
|
21677
|
+
/**
|
|
21678
|
+
* What one consultation of the dispatch-token endpoint returned: a token
|
|
21679
|
+
* reused from this process's cache (`reused`, no request made, so no trace)
|
|
21680
|
+
* or a fresh response. Reported only where that endpoint is consulted, never
|
|
21681
|
+
* for a token pre-minted at admission.
|
|
21682
|
+
*/
|
|
21683
|
+
type RunLedgerDispatchTokenObservation = {
|
|
21684
|
+
reused: boolean;
|
|
21685
|
+
trace: RunLedgerDispatchResponseTrace | null;
|
|
21686
|
+
};
|
|
21687
|
+
|
|
21688
|
+
/**
|
|
21689
|
+
* Where a delivery's app authority came from, for the slow-delivery record:
|
|
21690
|
+
* - `requested`: a dispatch-token request was made for this delivery, so
|
|
21691
|
+
* `authorityRequestId` names it when the receiver sent a platform id.
|
|
21692
|
+
* - `cached`: a dispatch token reused from this process or this drain.
|
|
21693
|
+
* - `pre_minted`: the run's admission-minted projection token.
|
|
21694
|
+
* - `local`: signed in-process or supplied by the caller.
|
|
21695
|
+
* Only `requested` makes an authority request; for every other source a null
|
|
21696
|
+
* `authorityRequestId` means no request happened, not a missing header.
|
|
21697
|
+
* `null` means the delivery ended before it had an authority.
|
|
21698
|
+
*/
|
|
21699
|
+
type RunLedgerDeliveryAuthoritySource =
|
|
21700
|
+
| 'requested'
|
|
21701
|
+
| 'cached'
|
|
21702
|
+
| 'pre_minted'
|
|
21703
|
+
| 'local';
|
|
21704
|
+
|
|
21705
|
+
function runLedgerDeliveryAuthoritySource(input: {
|
|
21706
|
+
authorityReady: boolean;
|
|
21707
|
+
tokenAuthority: RunLedgerOutboxTokenAuthority;
|
|
21708
|
+
reusedWithinDrain: boolean;
|
|
21709
|
+
token: RunLedgerDispatchTokenObservation | null;
|
|
21710
|
+
}): RunLedgerDeliveryAuthoritySource | null {
|
|
21711
|
+
if (!input.authorityReady) return null;
|
|
21712
|
+
if (input.tokenAuthority !== 'gateway') return 'local';
|
|
21713
|
+
if (input.token) return input.token.reused ? 'cached' : 'requested';
|
|
21714
|
+
return input.reusedWithinDrain ? 'cached' : 'pre_minted';
|
|
21715
|
+
}
|
|
21716
|
+
|
|
21717
|
+
function runLedgerSlowDeliveryResponseFields(
|
|
21718
|
+
authoritySource: RunLedgerDeliveryAuthoritySource | null,
|
|
21719
|
+
authority: RunLedgerDispatchResponseTrace | null,
|
|
21720
|
+
append:
|
|
21721
|
+
| (RunLedgerDispatchResponseTrace & { roundTripMs: number | null })
|
|
21722
|
+
| null,
|
|
21723
|
+
appendTransportAttemptId: string | null,
|
|
21724
|
+
): {
|
|
21725
|
+
authoritySource: RunLedgerDeliveryAuthoritySource | null;
|
|
21726
|
+
authorityRequestId: string | null;
|
|
21727
|
+
authorityServerTiming: string | null;
|
|
21728
|
+
appendRequestId: string | null;
|
|
21729
|
+
appendServerTiming: string | null;
|
|
21730
|
+
appendRoundTripMs: number | null;
|
|
21731
|
+
appendTransportAttemptId: string | null;
|
|
21732
|
+
} {
|
|
21733
|
+
return {
|
|
21734
|
+
authoritySource,
|
|
21735
|
+
authorityRequestId: authority?.platformRequestId ?? null,
|
|
21736
|
+
authorityServerTiming: authority?.serverTimingHeader ?? null,
|
|
21737
|
+
appendRequestId: append?.platformRequestId ?? null,
|
|
21738
|
+
appendServerTiming: append?.serverTimingHeader ?? null,
|
|
21739
|
+
appendRoundTripMs: append?.roundTripMs ?? null,
|
|
21740
|
+
// The id this delivery sent in its last append request's
|
|
21741
|
+
// transport-attempt header. Unlike the response fields above it is set
|
|
21742
|
+
// even when that request was aborted or never answered.
|
|
21743
|
+
appendTransportAttemptId,
|
|
21744
|
+
};
|
|
21745
|
+
}
|
|
21746
|
+
|
|
21501
21747
|
/**
|
|
21502
21748
|
* Admission persists an optional, run-scoped `run.ledger.project` token for the
|
|
21503
21749
|
* worker's terminal fast path. Treat it as usable only when its decoded claims
|
|
@@ -21600,6 +21846,8 @@ async function requestRunLedgerDispatchToken(
|
|
|
21600
21846
|
reused: boolean;
|
|
21601
21847
|
cacheKey: string;
|
|
21602
21848
|
runLedgerIngressPrefixBatching?: true;
|
|
21849
|
+
/** Present only when this call made the request (never for a reused token). */
|
|
21850
|
+
responseTrace?: RunLedgerDispatchResponseTrace;
|
|
21603
21851
|
}> {
|
|
21604
21852
|
const internalToken = process.env.DEEPLINE_INTERNAL_TOKEN?.trim();
|
|
21605
21853
|
if (!internalToken || !input.eventId || !input.leaseOwner) {
|
|
@@ -21750,6 +21998,16 @@ async function requestRunLedgerDispatchToken(
|
|
|
21750
21998
|
...(body.runLedgerIngressPrefixBatching === true
|
|
21751
21999
|
? { runLedgerIngressPrefixBatching: true as const }
|
|
21752
22000
|
: {}),
|
|
22001
|
+
responseTrace: {
|
|
22002
|
+
platformRequestId: readRuntimeApiDiagnosticHeader(
|
|
22003
|
+
response.headers,
|
|
22004
|
+
'x-vercel-id',
|
|
22005
|
+
),
|
|
22006
|
+
serverTimingHeader: readRuntimeApiDiagnosticHeader(
|
|
22007
|
+
response.headers,
|
|
22008
|
+
'server-timing',
|
|
22009
|
+
),
|
|
22010
|
+
},
|
|
21753
22011
|
};
|
|
21754
22012
|
}
|
|
21755
22013
|
|