deepline 0.3.289 → 0.3.290

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.
Files changed (44) hide show
  1. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  2. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +30 -10
  3. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +108 -12
  4. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +1 -1
  5. package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +1 -0
  6. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +3 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/launch-identity.ts +1 -0
  8. package/dist/bundling-sources/shared_libs/play-runtime/log-provenance.ts +17 -0
  9. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/worker-terminal-projection.ts +6 -5
  10. package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-batching-registry.ts +2 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +7 -0
  12. package/dist/bundling-sources/shared_libs/play-runtime/run-event-catalog.ts +2 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger-event-transport.ts +31 -3
  14. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +23 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/run-log-buffer.ts +30 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +38 -3
  17. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +2 -3
  18. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-terminal-push.ts +22 -1
  19. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +1 -1
  20. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +2 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-pool-options.ts +145 -0
  22. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +1 -5
  23. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +8 -139
  24. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +19 -5
  25. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +37 -15
  26. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +7 -5
  27. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +961 -281
  28. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +55 -25
  29. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-dispatch-authority.ts +97 -0
  30. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +33 -14
  31. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-event-search.ts +452 -43
  32. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-value-storage.ts +10 -1
  33. package/dist/bundling-sources/shared_libs/play-runtime/test-admission-batching.ts +103 -0
  34. package/dist/bundling-sources/shared_libs/play-runtime/zerobounce-batching.ts +75 -28
  35. package/dist/cli/index.js +3 -1
  36. package/dist/cli/index.mjs +3 -1
  37. package/dist/index.js +3 -1
  38. package/dist/index.mjs +3 -1
  39. package/dist/install-integrity.json +3 -0
  40. package/dist/release.d.mts +1 -1
  41. package/dist/release.d.ts +1 -1
  42. package/dist/release.js +1 -1
  43. package/dist/release.mjs +1 -1
  44. package/package.json +1 -1
@@ -964,6 +964,51 @@ export function createReceiptGatewayDispatcher(input: {
964
964
  }
965
965
  }
966
966
 
967
+ // Value preparation can wait on the writer fence or object storage. Finish
968
+ // it before checking out a SQL client, including the legacy single and
969
+ // injected-failure paths, so it cannot hold the pool needed by the fence.
970
+ let preparedCompletion: ReceiptCompletionOutputWithPersistence | null =
971
+ null;
972
+ let preparedCompletions: ReceiptGatewayCompletionEntry[] | null = null;
973
+ if (body.action === 'complete_runtime_step_receipt') {
974
+ const key = receiptKey(body.key);
975
+ if (key instanceof Response) return key;
976
+ completionFaultInjected =
977
+ (await input.consumeReceiptCompleteFault?.(runId)) === true;
978
+ if (!completionFaultInjected) {
979
+ preparedCompletion = await receiptCompletionOutput({
980
+ orgId: scope.orgId,
981
+ key,
982
+ output: body.output,
983
+ inlineFields: body.inlineFields,
984
+ persist: persistReceiptValue,
985
+ });
986
+ observeReceiptValuePersistence(
987
+ [preparedCompletion],
988
+ input.onReceiptValuePersistence,
989
+ );
990
+ }
991
+ } else if (body.action === 'complete_runtime_step_receipts') {
992
+ const sameRunError = requireSameRunReceipts(runId, body.receipts);
993
+ if (sameRunError) return sameRunError;
994
+ const keys = receiptKeys(
995
+ (body.receipts as Array<Record<string, unknown>>).map(
996
+ (receipt) => receipt.key,
997
+ ),
998
+ );
999
+ if (keys instanceof Response) return keys;
1000
+ preparedCompletions = await buildReceiptCompletions({
1001
+ orgId: scope.orgId,
1002
+ persist: persistReceiptValue,
1003
+ receipts: body.receipts,
1004
+ keys,
1005
+ runId,
1006
+ onValuePersistence: input.onReceiptValuePersistence,
1007
+ });
1008
+ completionFaultInjected ??=
1009
+ (await input.consumeReceiptCompleteFault?.(runId)) === true;
1010
+ }
1011
+
967
1012
  return await input.withClient(async (client) => {
968
1013
  switch (body.action) {
969
1014
  case 'get_runtime_step_receipt': {
@@ -1099,7 +1144,7 @@ export function createReceiptGatewayDispatcher(input: {
1099
1144
  case 'complete_runtime_step_receipt': {
1100
1145
  const key = receiptKey(body.key);
1101
1146
  if (key instanceof Response) return key;
1102
- if (await input.consumeReceiptCompleteFault?.(runId)) {
1147
+ if (completionFaultInjected) {
1103
1148
  await injectReceiptCompletionFailure({
1104
1149
  client,
1105
1150
  orgId: scope.orgId,
@@ -1116,22 +1161,14 @@ export function createReceiptGatewayDispatcher(input: {
1116
1161
  { status: 409 },
1117
1162
  );
1118
1163
  }
1119
- const completionOutput = await receiptCompletionOutput({
1120
- orgId: scope.orgId,
1121
- key,
1122
- output: body.output,
1123
- inlineFields: body.inlineFields,
1124
- persist: persistReceiptValue,
1125
- });
1126
- observeReceiptValuePersistence(
1127
- [completionOutput],
1128
- input.onReceiptValuePersistence,
1129
- );
1164
+ if (!preparedCompletion) {
1165
+ throw new Error('Receipt completion value was not prepared.');
1166
+ }
1130
1167
  const {
1131
1168
  valuePersistMs: _valuePersistMs,
1132
1169
  valuePersistedByReference: _valuePersistedByReference,
1133
1170
  ...storedCompletionOutput
1134
- } = completionOutput;
1171
+ } = preparedCompletion;
1135
1172
  const completed = await completePostgresSchedulerReceipt(
1136
1173
  client,
1137
1174
  {
@@ -1165,18 +1202,11 @@ export function createReceiptGatewayDispatcher(input: {
1165
1202
  ),
1166
1203
  );
1167
1204
  if (keys instanceof Response) return keys;
1168
- const completions = await buildReceiptCompletions({
1169
- orgId: scope.orgId,
1170
- persist: persistReceiptValue,
1171
- receipts: body.receipts,
1172
- keys,
1173
- runId,
1174
- onValuePersistence: input.onReceiptValuePersistence,
1175
- });
1176
- if (
1177
- completionFaultInjected ??
1178
- (await input.consumeReceiptCompleteFault?.(runId))
1179
- ) {
1205
+ if (!preparedCompletions) {
1206
+ throw new Error('Receipt completion values were not prepared.');
1207
+ }
1208
+ const completions = preparedCompletions;
1209
+ if (completionFaultInjected) {
1180
1210
  const [skippedReceipt, ...siblingReceipts] = completions;
1181
1211
  if (siblingReceipts.length > 0) {
1182
1212
  await completePostgresSchedulerReceipts(
@@ -0,0 +1,97 @@
1
+ import type { PlaySchedulerSubmitInput } from '../scheduler-backend';
2
+ import { PROD_DEFAULT_RUNTIME_SCHEDULER_SCHEMA } from '../runtime-scheduler-topology';
3
+ import { resolveRuntimeSchedulerSchemaEnv } from './runtime-scheduler-schema';
4
+ import type {
5
+ PostgresSchedulerOptions,
6
+ PostgresSchedulerQueryClient,
7
+ } from './postgres';
8
+
9
+ export type RunLedgerDispatchLaunch = Pick<
10
+ PlaySchedulerSubmitInput,
11
+ | 'runId'
12
+ | 'playId'
13
+ | 'playName'
14
+ | 'executorToken'
15
+ | 'baseUrl'
16
+ | 'runtimeApiBaseUrl'
17
+ | 'runtimeTokenOrigin'
18
+ | 'orgId'
19
+ | 'runtimeAuthority'
20
+ | 'vercelProtectionBypassToken'
21
+ >;
22
+
23
+ /** Authority reads never transfer customer input, artifacts or execution graphs. */
24
+ export function runLedgerDispatchLaunchSql(alias: string): string {
25
+ const fields: (keyof RunLedgerDispatchLaunch)[] = [
26
+ 'runId',
27
+ 'playId',
28
+ 'playName',
29
+ 'executorToken',
30
+ 'baseUrl',
31
+ 'runtimeApiBaseUrl',
32
+ 'runtimeTokenOrigin',
33
+ 'orgId',
34
+ 'runtimeAuthority',
35
+ 'vercelProtectionBypassToken',
36
+ ];
37
+ return `jsonb_build_object(${fields
38
+ .map((field) => `'${field}', ${alias}.launch_json->'${field}'`)
39
+ .join(', ')})`;
40
+ }
41
+
42
+ function dispatchTableName(
43
+ table: string,
44
+ options?: Pick<PostgresSchedulerOptions, 'schema'>,
45
+ ): string {
46
+ const schema =
47
+ options?.schema?.trim() ||
48
+ resolveRuntimeSchedulerSchemaEnv() ||
49
+ PROD_DEFAULT_RUNTIME_SCHEDULER_SCHEMA;
50
+ const quote = (name: string) => `"${name.replace(/"/g, '""')}"`;
51
+ return `${quote(schema)}.${quote(table)}`;
52
+ }
53
+
54
+ export function parseRunLedgerDispatchLaunch(
55
+ value: unknown,
56
+ ): RunLedgerDispatchLaunch {
57
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
58
+ throw new Error('Postgres scheduler launch_json is not an object.');
59
+ }
60
+ const launch = value as Partial<PlaySchedulerSubmitInput>;
61
+ if (
62
+ typeof launch.runId !== 'string' ||
63
+ typeof launch.playId !== 'string' ||
64
+ typeof launch.playName !== 'string' ||
65
+ typeof launch.executorToken !== 'string' ||
66
+ typeof launch.baseUrl !== 'string'
67
+ ) {
68
+ throw new Error(
69
+ 'Postgres scheduler launch_json is missing required fields.',
70
+ );
71
+ }
72
+ return launch as RunLedgerDispatchLaunch;
73
+ }
74
+
75
+ /** Read only the immutable authority/routing fields under the same lease fence. */
76
+ export async function readRunLedgerDispatchAuthorityForLease(
77
+ client: PostgresSchedulerQueryClient,
78
+ input: { runId: string; eventId: string; leaseOwner: string },
79
+ options?: Pick<PostgresSchedulerOptions, 'schema'>,
80
+ ): Promise<RunLedgerDispatchLaunch | null> {
81
+ const result = await client.query<{ launch_json: unknown }>(
82
+ `SELECT ${runLedgerDispatchLaunchSql('runs')} AS launch_json
83
+ FROM ${dispatchTableName('outbox', options)} outbox
84
+ JOIN ${dispatchTableName('runs', options)} runs ON runs.run_id = outbox.run_id
85
+ WHERE outbox.event_id = $1
86
+ AND outbox.run_id = $2
87
+ AND outbox.lease_owner = $3
88
+ AND outbox.lease_expires_at > now()
89
+ AND outbox.delivered_at IS NULL
90
+ AND outbox.failed_at IS NULL
91
+ LIMIT 1`,
92
+ [input.eventId, input.runId, input.leaseOwner],
93
+ );
94
+ return result.rows[0]
95
+ ? parseRunLedgerDispatchLaunch(result.rows[0].launch_json)
96
+ : null;
97
+ }
@@ -583,6 +583,12 @@ export function startRunLedgerOutboxRecoveryController(input: {
583
583
  onDelivered?: (deliveries: readonly RunLedgerOutboxDeliveredRow[]) => void;
584
584
  }): RunLedgerOutboxRecoveryController {
585
585
  const schedulerOptions = input.schedulerOptions ?? {};
586
+ let dispatchOrdinal = 0;
587
+ let searchInFlight = 0;
588
+ const maxSearchInFlight = Math.max(
589
+ 1,
590
+ Math.floor(RUN_LEDGER_OUTBOX_RECOVERY_PRODUCTION_IN_FLIGHT / 2),
591
+ );
586
592
  return startRunLedgerOutboxRecovery({
587
593
  acquireNotifyHub: () =>
588
594
  input.useDirectNotify === false
@@ -593,20 +599,33 @@ export function startRunLedgerOutboxRecoveryController(input: {
593
599
  schedulerOptions,
594
600
  }),
595
601
  ),
596
- dispatchOnce: (headPriority) =>
597
- dispatchRunLedgerOutboxToLedgerBatchOnceWithClientScope(
598
- (operation) => withRuntimeSchedulerClient(input.poolOptions, operation),
599
- {
600
- tokenAuthority: 'gateway',
601
- limit: 8,
602
- headPriority,
603
- // The lease holder delivers a run's terminal committed during its
604
- // append, instead of leaving it for the next wave.
605
- continueThroughTerminal: true,
606
- ...(input.onDelivered ? { onDelivered: input.onDelivered } : {}),
607
- },
608
- schedulerOptions,
609
- ),
602
+ dispatchOnce: async (headPriority) => {
603
+ const searchOnly =
604
+ dispatchOrdinal++ % 2 === 1 && searchInFlight < maxSearchInFlight;
605
+ if (searchOnly) searchInFlight += 1;
606
+ try {
607
+ return await dispatchRunLedgerOutboxToLedgerBatchOnceWithClientScope(
608
+ (operation) =>
609
+ withRuntimeSchedulerClient(input.poolOptions, operation),
610
+ {
611
+ tokenAuthority: 'gateway',
612
+ materializeObservability: true,
613
+ // One durable controller, with half its capacity reserved for
614
+ // lifecycle delivery even when every search operation is blocked.
615
+ searchOnly,
616
+ limit: 8,
617
+ headPriority,
618
+ // The lease holder delivers a run's terminal committed during its
619
+ // append, instead of leaving it for the next wave.
620
+ continueThroughTerminal: true,
621
+ ...(input.onDelivered ? { onDelivered: input.onDelivered } : {}),
622
+ },
623
+ schedulerOptions,
624
+ );
625
+ } finally {
626
+ if (searchOnly) searchInFlight -= 1;
627
+ }
628
+ },
610
629
  // `dispatchRunLedgerOutboxToLedgerBatchOnceWithClientScope` releases each
611
630
  // short scheduler checkout before it calls the Vercel gateway. The two
612
631
  // replicas therefore drain up to sixteen independent runs concurrently