@intx/db 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +176 -0
- package/README.md +23 -4
- package/dist/approval-store.d.ts +52 -0
- package/dist/approval-store.js +79 -0
- package/dist/asset-resolution.d.ts +52 -0
- package/dist/asset-resolution.js +66 -0
- package/dist/catalog-resolution.d.ts +76 -0
- package/dist/catalog-resolution.js +151 -0
- package/dist/client.d.ts +19 -0
- package/dist/client.js +18 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +16 -0
- package/dist/connection.d.ts +3 -0
- package/dist/connection.js +26 -0
- package/dist/credential-resolution.d.ts +222 -0
- package/dist/credential-resolution.js +255 -0
- package/dist/grant-store.d.ts +3 -0
- package/dist/grant-store.js +59 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +20 -0
- package/dist/migrate.d.ts +36 -0
- package/dist/migrate.js +135 -0
- package/dist/model-source-resolution.d.ts +115 -0
- package/dist/model-source-resolution.js +291 -0
- package/dist/parse-row.d.ts +373 -0
- package/dist/parse-row.js +232 -0
- package/dist/pg-error.d.ts +3 -0
- package/dist/pg-error.js +19 -0
- package/dist/pricing.d.ts +15 -0
- package/dist/pricing.js +24 -0
- package/dist/rekey-credential-secrets.d.ts +13 -0
- package/dist/rekey-credential-secrets.js +61 -0
- package/dist/schema/approvals.d.ts +245 -0
- package/dist/schema/approvals.js +52 -0
- package/dist/schema/assets.d.ts +143 -0
- package/{src/schema/assets.ts → dist/schema/assets.js} +7 -16
- package/dist/schema/auth.d.ts +606 -0
- package/dist/schema/auth.js +47 -0
- package/dist/schema/catalog.d.ts +811 -0
- package/dist/schema/catalog.js +108 -0
- package/dist/schema/column-types.d.ts +26 -0
- package/dist/schema/column-types.js +15 -0
- package/dist/schema/credentials.d.ts +305 -0
- package/{src/schema/credentials.ts → dist/schema/credentials.js} +16 -22
- package/dist/schema/git-tokens.d.ts +256 -0
- package/{src/schema/git-tokens.ts → dist/schema/git-tokens.js} +16 -39
- package/dist/schema/grants.d.ts +211 -0
- package/dist/schema/grants.js +30 -0
- package/dist/schema/index.d.ts +25 -0
- package/dist/schema/index.js +25 -0
- package/dist/schema/messages.d.ts +414 -0
- package/dist/schema/messages.js +82 -0
- package/dist/schema/oauth-clients.d.ts +246 -0
- package/{src/schema/oauth-clients.ts → dist/schema/oauth-clients.js} +8 -14
- package/dist/schema/offerings.d.ts +160 -0
- package/dist/schema/offerings.js +24 -0
- package/dist/schema/principals.d.ts +128 -0
- package/dist/schema/principals.js +23 -0
- package/dist/schema/providers.d.ts +237 -0
- package/dist/schema/providers.js +22 -0
- package/dist/schema/roles.d.ts +242 -0
- package/dist/schema/roles.js +37 -0
- package/dist/schema/session-assets.d.ts +92 -0
- package/dist/schema/session-assets.js +45 -0
- package/dist/schema/sessions.d.ts +143 -0
- package/dist/schema/sessions.js +29 -0
- package/dist/schema/sidecar-allocation.d.ts +406 -0
- package/dist/schema/sidecar-allocation.js +57 -0
- package/dist/schema/sidecar.d.ts +145 -0
- package/dist/schema/sidecar.js +28 -0
- package/dist/schema/signal-correlations.d.ts +177 -0
- package/dist/schema/signal-correlations.js +31 -0
- package/dist/schema/tenants.d.ts +235 -0
- package/{src/schema/tenants.ts → dist/schema/tenants.js} +10 -27
- package/dist/schema/wallets.d.ts +354 -0
- package/dist/schema/wallets.js +43 -0
- package/dist/schema/workflow-definitions.d.ts +371 -0
- package/dist/schema/workflow-definitions.js +97 -0
- package/dist/schema/workflow-run-dispatch.d.ts +328 -0
- package/dist/schema/workflow-run-dispatch.js +56 -0
- package/dist/schema/workflow-run-execution.d.ts +126 -0
- package/dist/schema/workflow-run-execution.js +48 -0
- package/dist/schema/workflow-run-launch-spec.d.ts +200 -0
- package/dist/schema/workflow-run-launch-spec.js +26 -0
- package/dist/schema/workflow-run.d.ts +230 -0
- package/dist/schema/workflow-run.js +102 -0
- package/dist/sidecar-allocation-store.d.ts +171 -0
- package/dist/sidecar-allocation-store.js +512 -0
- package/dist/signal-correlation-store.d.ts +36 -0
- package/dist/signal-correlation-store.js +63 -0
- package/dist/tenant-hierarchy.d.ts +23 -0
- package/dist/tenant-hierarchy.js +60 -0
- package/dist/workflow-definition-store.d.ts +55 -0
- package/dist/workflow-definition-store.js +93 -0
- package/dist/workflow-run-dispatch-store.d.ts +80 -0
- package/dist/workflow-run-dispatch-store.js +298 -0
- package/dist/workflow-run-launch-spec-store.d.ts +13 -0
- package/dist/workflow-run-launch-spec-store.js +30 -0
- package/dist/workflow-run-store.d.ts +54 -0
- package/dist/workflow-run-store.js +85 -0
- package/migrations/0029_loose_warlock.sql +1 -0
- package/migrations/0030_session_asset_audit_split.sql +5 -0
- package/migrations/0031_gigantic_nicolaos.sql +68 -0
- package/migrations/0032_lethal_misty_knight.sql +1 -0
- package/migrations/0033_old_payback.sql +1 -0
- package/migrations/0034_sleepy_songbird.sql +11 -0
- package/migrations/0035_violet_giant_man.sql +3 -0
- package/migrations/0036_sharp_the_executioner.sql +2 -0
- package/migrations/0037_credential_use_backfill.sql +39 -0
- package/migrations/0038_chilly_blacklash.sql +37 -0
- package/migrations/0039_quick_carnage.sql +2 -0
- package/migrations/0040_reshape_approval_origin.sql +24 -0
- package/migrations/0041_make_approval_timeout_at_nullable.sql +1 -0
- package/migrations/0042_youthful_mantis.sql +2 -0
- package/migrations/0043_signal_correlation_deployment_fk.sql +1 -0
- package/migrations/0044_model_offering_quirks.sql +1 -0
- package/migrations/0045_create_workflow_run.sql +13 -0
- package/migrations/0046_approval_signal_correlation_run_fk.sql +2 -0
- package/migrations/0047_create_workflow_definition.sql +30 -0
- package/migrations/0048_workflow_definition_origin_agent_id.sql +2 -0
- package/migrations/0049_curly_omega_flight.sql +2 -0
- package/migrations/0050_late_crystal.sql +10 -0
- package/migrations/0051_funny_madelyne_pryor.sql +1 -0
- package/migrations/0052_drop_inference_turn_instance_fk.sql +1 -0
- package/migrations/0053_session_mail_session_id_index.sql +1 -0
- package/migrations/0054_rekey_instance_grants_to_workflow_run.sql +10 -0
- package/migrations/0055_backfill_anchor_workflow_runs.sql +69 -0
- package/migrations/0056_repoint_deployment_fks_to_anchor_run.sql +32 -0
- package/migrations/0057_drop_workflow_deployment_projection.sql +22 -0
- package/migrations/0058_repoint_offering_fk_to_definition.sql +41 -0
- package/migrations/0059_repoint_transaction_fk_to_run.sql +10 -0
- package/migrations/0060_drop_session_mail_instance_fk.sql +6 -0
- package/migrations/0061_drop_session_asset_instance_fk.sql +7 -0
- package/migrations/0062_drop_agent_asset_table.sql +11 -0
- package/migrations/0063_repoint_agent_role_fk_to_definition.sql +39 -0
- package/migrations/0064_repoint_agent_session_fk_to_definition.sql +47 -0
- package/migrations/0065_add_workflow_definition_model_requirements.sql +37 -0
- package/migrations/0066_rekey_agent_definition_principals_to_workflow.sql +27 -0
- package/migrations/0067_add_workflow_definition_kind.sql +10 -0
- package/migrations/0068_drop_agent_tables_and_origin_agent_id.sql +31 -0
- package/migrations/0069_drop_workflow_definition_kind.sql +10 -0
- package/migrations/0070_flashy_proteus.sql +13 -0
- package/migrations/0072_add_workflow_definition_credential_bindings.sql +1 -0
- package/migrations/0073_grant_target_exactly_one_check.sql +13 -0
- package/migrations/0074_add_provider_api_base_url.sql +1 -0
- package/migrations/0075_workflow_run_launch_spec.sql +17 -0
- package/migrations/0076_sidecar_allocation.sql +40 -0
- package/migrations/0077_workflow_run_dispatch.sql +29 -0
- package/migrations/0078_workflow_run_dispatch_kind.sql +2 -0
- package/migrations/0079_rename_workflow_run_deployment_id_to_anchor_run_id.sql +4 -0
- package/migrations/0080_rename_correlation_approval_deployment_id_to_anchor_run_id.sql +9 -0
- package/migrations/0081_workflow_definition_content_hash_and_approved_wire_hash.sql +4 -0
- package/migrations/0082_blue_black_queen.sql +1 -0
- package/migrations/0083_replace_launch_spec_snapshot_with_frozen_bundle.sql +3 -0
- package/migrations/0084_delete_orphaned_credential_grants.sql +22 -0
- package/migrations/meta/0029_snapshot.json +2664 -0
- package/migrations/meta/0030_snapshot.json +2670 -0
- package/migrations/meta/0031_snapshot.json +3100 -0
- package/migrations/meta/0032_snapshot.json +3106 -0
- package/migrations/meta/0033_snapshot.json +3112 -0
- package/migrations/meta/0034_snapshot.json +3198 -0
- package/migrations/meta/0035_snapshot.json +3225 -0
- package/migrations/meta/0036_snapshot.json +3237 -0
- package/migrations/meta/0037_snapshot.json +3237 -0
- package/migrations/meta/0038_snapshot.json +3470 -0
- package/migrations/meta/0039_snapshot.json +3470 -0
- package/migrations/meta/0040_snapshot.json +3489 -0
- package/migrations/meta/0041_snapshot.json +3489 -0
- package/migrations/meta/0042_snapshot.json +3489 -0
- package/migrations/meta/0043_snapshot.json +3498 -0
- package/migrations/meta/0044_snapshot.json +3504 -0
- package/migrations/meta/0045_snapshot.json +3589 -0
- package/migrations/meta/0046_snapshot.json +3607 -0
- package/migrations/meta/0047_snapshot.json +3832 -0
- package/migrations/meta/0048_snapshot.json +3853 -0
- package/migrations/meta/0049_snapshot.json +3854 -0
- package/migrations/meta/0050_snapshot.json +3924 -0
- package/migrations/meta/0051_snapshot.json +3940 -0
- package/migrations/meta/0052_snapshot.json +3931 -0
- package/migrations/meta/0053_snapshot.json +3952 -0
- package/migrations/meta/0054_snapshot.json +3952 -0
- package/migrations/meta/0055_snapshot.json +3952 -0
- package/migrations/meta/0056_snapshot.json +3952 -0
- package/migrations/meta/0057_snapshot.json +3839 -0
- package/migrations/meta/0058_snapshot.json +3839 -0
- package/migrations/meta/0059_snapshot.json +3839 -0
- package/migrations/meta/0060_snapshot.json +3830 -0
- package/migrations/meta/0061_snapshot.json +3821 -0
- package/migrations/meta/0062_snapshot.json +3723 -0
- package/migrations/meta/0063_snapshot.json +3723 -0
- package/migrations/meta/0064_snapshot.json +3723 -0
- package/migrations/meta/0065_snapshot.json +3729 -0
- package/migrations/meta/0066_snapshot.json +3729 -0
- package/migrations/meta/0067_snapshot.json +3736 -0
- package/migrations/meta/0068_snapshot.json +3347 -0
- package/migrations/meta/0069_snapshot.json +3340 -0
- package/migrations/meta/0070_snapshot.json +3444 -0
- package/migrations/meta/0072_snapshot.json +3450 -0
- package/migrations/meta/0073_snapshot.json +3455 -0
- package/migrations/meta/0074_snapshot.json +3461 -0
- package/migrations/meta/0075_snapshot.json +3567 -0
- package/migrations/meta/0076_snapshot.json +3851 -0
- package/migrations/meta/0077_snapshot.json +4067 -0
- package/migrations/meta/0078_snapshot.json +4078 -0
- package/migrations/meta/0079_snapshot.json +4078 -0
- package/migrations/meta/0080_snapshot.json +4078 -0
- package/migrations/meta/0081_snapshot.json +4096 -0
- package/migrations/meta/0082_snapshot.json +4102 -0
- package/migrations/meta/0083_snapshot.json +4096 -0
- package/migrations/meta/0084_snapshot.json +4096 -0
- package/migrations/meta/_journal.json +385 -0
- package/package.json +25 -11
- package/drizzle.config.ts +0 -23
- package/src/client.ts +0 -24
- package/src/config.ts +0 -19
- package/src/connection.ts +0 -27
- package/src/credential-resolution.ts +0 -378
- package/src/grant-store.ts +0 -51
- package/src/index.ts +0 -32
- package/src/migrate.test.ts +0 -35
- package/src/migrate.ts +0 -168
- package/src/parse-row.test.ts +0 -113
- package/src/parse-row.ts +0 -185
- package/src/schema/agent-assets.ts +0 -21
- package/src/schema/agents.ts +0 -49
- package/src/schema/auth.ts +0 -51
- package/src/schema/grants.ts +0 -26
- package/src/schema/index.ts +0 -19
- package/src/schema/instances.ts +0 -36
- package/src/schema/messages.ts +0 -108
- package/src/schema/offerings.ts +0 -20
- package/src/schema/principals.ts +0 -28
- package/src/schema/providers.ts +0 -23
- package/src/schema/roles.ts +0 -51
- package/src/schema/session-assets.ts +0 -49
- package/src/schema/sessions.ts +0 -26
- package/src/schema/sidecar.ts +0 -14
- package/src/schema/wallets.ts +0 -44
- package/src/tenant-hierarchy.ts +0 -34
- package/tsconfig.json +0 -4
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { SidecarPlacementRequirement, type SidecarAllocationStatus } from "@intx/types";
|
|
2
|
+
import type { DB, DBExecutor } from "./client.js";
|
|
3
|
+
type DBHandle = DB["db"];
|
|
4
|
+
declare const activeStatuses: readonly ["pending", "provisioning", "allocated", "replacing", "releasing"];
|
|
5
|
+
export type SidecarAllocation = {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly anchorRunId: string;
|
|
8
|
+
readonly tenantId: string;
|
|
9
|
+
readonly provisionerId: string;
|
|
10
|
+
readonly provisionerApiVersion: 1;
|
|
11
|
+
readonly provisionerBindingFingerprint: string;
|
|
12
|
+
readonly sidecarId?: string;
|
|
13
|
+
readonly placement: SidecarPlacementRequirement;
|
|
14
|
+
readonly status: SidecarAllocationStatus;
|
|
15
|
+
readonly generation: number;
|
|
16
|
+
readonly ensureAcceptedGeneration?: number;
|
|
17
|
+
readonly externalRef?: string;
|
|
18
|
+
readonly nextAttemptAt?: Date;
|
|
19
|
+
readonly reconciliationLeaseId?: string;
|
|
20
|
+
readonly reconciliationLeaseExpiresAt?: Date;
|
|
21
|
+
readonly ensureAttempts: number;
|
|
22
|
+
readonly destroyAttempts: number;
|
|
23
|
+
readonly connectDeadline?: Date;
|
|
24
|
+
readonly failureCode?: string;
|
|
25
|
+
readonly failureMessage?: string;
|
|
26
|
+
readonly createdAt: Date;
|
|
27
|
+
readonly updatedAt: Date;
|
|
28
|
+
};
|
|
29
|
+
export type CreatePendingSidecarAllocationArgs = {
|
|
30
|
+
readonly id: string;
|
|
31
|
+
readonly anchorRunId: string;
|
|
32
|
+
readonly tenantId: string;
|
|
33
|
+
readonly provisionerId: string;
|
|
34
|
+
readonly provisionerApiVersion: 1;
|
|
35
|
+
readonly provisionerBindingFingerprint: string;
|
|
36
|
+
readonly placement?: SidecarPlacementRequirement;
|
|
37
|
+
readonly now?: Date;
|
|
38
|
+
};
|
|
39
|
+
export type ClaimSidecarAllocationArgs = {
|
|
40
|
+
readonly leaseId: string;
|
|
41
|
+
readonly leaseDurationMs: number;
|
|
42
|
+
};
|
|
43
|
+
export type ParkSidecarReconciliationPolicy = {
|
|
44
|
+
readonly kind: "await-connection";
|
|
45
|
+
readonly fallbackNextAttemptAt: Date;
|
|
46
|
+
} | {
|
|
47
|
+
readonly kind: "retry-after-error";
|
|
48
|
+
readonly notBefore: Date;
|
|
49
|
+
};
|
|
50
|
+
export type BindInitialSidecarArgs = {
|
|
51
|
+
readonly allocationId: string;
|
|
52
|
+
readonly expectedGeneration: number;
|
|
53
|
+
readonly sidecarId: string;
|
|
54
|
+
readonly tokenHashSha256: Uint8Array;
|
|
55
|
+
readonly connectDeadline: Date;
|
|
56
|
+
readonly expectedLeaseId?: string;
|
|
57
|
+
readonly now?: Date;
|
|
58
|
+
};
|
|
59
|
+
export type BindReplacementSidecarArgs = {
|
|
60
|
+
readonly allocationId: string;
|
|
61
|
+
readonly generation: number;
|
|
62
|
+
readonly sidecarId: string;
|
|
63
|
+
readonly tokenHashSha256: Uint8Array;
|
|
64
|
+
readonly connectDeadline: Date;
|
|
65
|
+
readonly expectedLeaseId?: string;
|
|
66
|
+
readonly now?: Date;
|
|
67
|
+
};
|
|
68
|
+
export type MarkSidecarAllocatedArgs = {
|
|
69
|
+
readonly allocationId: string;
|
|
70
|
+
readonly generation: number;
|
|
71
|
+
readonly externalRef?: string;
|
|
72
|
+
readonly expectedLeaseId?: string;
|
|
73
|
+
readonly now?: Date;
|
|
74
|
+
};
|
|
75
|
+
export type ScheduleSidecarAllocationRetryArgs = {
|
|
76
|
+
readonly allocationId: string;
|
|
77
|
+
readonly expectedStatus: (typeof activeStatuses)[number];
|
|
78
|
+
readonly expectedGeneration: number;
|
|
79
|
+
readonly nextAttemptAt: Date;
|
|
80
|
+
readonly expectedLeaseId?: string;
|
|
81
|
+
readonly attempt?: "ensure" | "destroy";
|
|
82
|
+
readonly failure?: {
|
|
83
|
+
readonly code: string;
|
|
84
|
+
readonly message: string;
|
|
85
|
+
};
|
|
86
|
+
readonly now?: Date;
|
|
87
|
+
};
|
|
88
|
+
export type BeginSidecarReplacementArgs = {
|
|
89
|
+
readonly allocationId: string;
|
|
90
|
+
readonly expectedStatus: "provisioning" | "allocated";
|
|
91
|
+
readonly expectedGeneration: number;
|
|
92
|
+
readonly expectedLeaseId: string;
|
|
93
|
+
readonly nextAttemptAt: Date;
|
|
94
|
+
readonly failureCode: string;
|
|
95
|
+
readonly failureMessage: string;
|
|
96
|
+
readonly now?: Date;
|
|
97
|
+
};
|
|
98
|
+
export type BeginSidecarReleaseArgs = {
|
|
99
|
+
readonly allocationId: string;
|
|
100
|
+
readonly expectedStatus: Exclude<(typeof activeStatuses)[number], "releasing">;
|
|
101
|
+
readonly expectedGeneration: number;
|
|
102
|
+
readonly failureCode?: string;
|
|
103
|
+
readonly failureMessage?: string;
|
|
104
|
+
readonly expectedLeaseId?: string;
|
|
105
|
+
readonly now?: Date;
|
|
106
|
+
};
|
|
107
|
+
export type BeginUnrecoverableSidecarReleaseArgs = {
|
|
108
|
+
readonly allocationId: string;
|
|
109
|
+
readonly expectedGeneration: number;
|
|
110
|
+
readonly expectedLeaseId: string;
|
|
111
|
+
readonly failureCode: string;
|
|
112
|
+
readonly failureMessage: string;
|
|
113
|
+
readonly now?: Date;
|
|
114
|
+
};
|
|
115
|
+
export type MarkSidecarReleasedArgs = {
|
|
116
|
+
readonly allocationId: string;
|
|
117
|
+
readonly generation: number;
|
|
118
|
+
readonly expectedLeaseId?: string;
|
|
119
|
+
readonly now?: Date;
|
|
120
|
+
};
|
|
121
|
+
export type MarkSidecarConnectionReadyArgs = {
|
|
122
|
+
readonly allocationId: string;
|
|
123
|
+
readonly generation: number;
|
|
124
|
+
readonly expectedLeaseId?: string;
|
|
125
|
+
readonly now?: Date;
|
|
126
|
+
};
|
|
127
|
+
export type MarkSidecarConnectionLostArgs = {
|
|
128
|
+
readonly allocationId: string;
|
|
129
|
+
readonly generation: number;
|
|
130
|
+
readonly connectDeadline: Date;
|
|
131
|
+
readonly now?: Date;
|
|
132
|
+
};
|
|
133
|
+
export type ScheduleSidecarReconnectIfUnscheduledArgs = {
|
|
134
|
+
readonly allocationId: string;
|
|
135
|
+
readonly generation: number;
|
|
136
|
+
readonly connectDeadline: Date;
|
|
137
|
+
readonly now?: Date;
|
|
138
|
+
};
|
|
139
|
+
export type FailSidecarAllocationArgs = {
|
|
140
|
+
readonly allocationId: string;
|
|
141
|
+
readonly expectedStatus: "pending" | "provisioning";
|
|
142
|
+
readonly expectedGeneration: number;
|
|
143
|
+
readonly code: string;
|
|
144
|
+
readonly message: string;
|
|
145
|
+
readonly expectedLeaseId?: string;
|
|
146
|
+
readonly now?: Date;
|
|
147
|
+
};
|
|
148
|
+
export declare function createSidecarAllocationStore(db: DBHandle): {
|
|
149
|
+
createPending(args: CreatePendingSidecarAllocationArgs, tx?: DBExecutor): Promise<SidecarAllocation>;
|
|
150
|
+
bindInitialSidecar(args: BindInitialSidecarArgs): Promise<SidecarAllocation | null>;
|
|
151
|
+
bindReplacementSidecar(args: BindReplacementSidecarArgs): Promise<SidecarAllocation | null>;
|
|
152
|
+
markAllocated(args: MarkSidecarAllocatedArgs): Promise<SidecarAllocation | null>;
|
|
153
|
+
scheduleRetry(args: ScheduleSidecarAllocationRetryArgs): Promise<SidecarAllocation | null>;
|
|
154
|
+
beginReplacement(args: BeginSidecarReplacementArgs): Promise<SidecarAllocation | null>;
|
|
155
|
+
beginRelease: (args: BeginSidecarReleaseArgs, tx?: DBExecutor) => Promise<SidecarAllocation | null>;
|
|
156
|
+
beginUnrecoverableRelease(args: BeginUnrecoverableSidecarReleaseArgs): Promise<SidecarAllocation | null>;
|
|
157
|
+
markReleased(args: MarkSidecarReleasedArgs): Promise<SidecarAllocation | null>;
|
|
158
|
+
failWithoutInfrastructure(args: FailSidecarAllocationArgs, tx?: DBExecutor): Promise<SidecarAllocation | null>;
|
|
159
|
+
findById(id: string): Promise<SidecarAllocation | null>;
|
|
160
|
+
findByAnchorRunId(anchorRunId: string): Promise<SidecarAllocation | null>;
|
|
161
|
+
claimNextReconcilable(args: ClaimSidecarAllocationArgs): Promise<SidecarAllocation | null>;
|
|
162
|
+
extendReconciliationLease(allocationId: string, leaseId: string, leaseDurationMs: number): Promise<boolean>;
|
|
163
|
+
markConnectionReady(args: MarkSidecarConnectionReadyArgs): Promise<SidecarAllocation | null>;
|
|
164
|
+
markConnectionLost(args: MarkSidecarConnectionLostArgs): Promise<SidecarAllocation | null>;
|
|
165
|
+
scheduleReconnectIfUnscheduled(args: ScheduleSidecarReconnectIfUnscheduledArgs): Promise<SidecarAllocation | null>;
|
|
166
|
+
parkReconciliation(allocationId: string, leaseId: string, policy: ParkSidecarReconciliationPolicy): Promise<boolean>;
|
|
167
|
+
wakeReconciliation(allocationId: string, generation: number): Promise<boolean>;
|
|
168
|
+
listActive(): Promise<SidecarAllocation[]>;
|
|
169
|
+
};
|
|
170
|
+
export type SidecarAllocationStore = ReturnType<typeof createSidecarAllocationStore>;
|
|
171
|
+
export {};
|
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
import { type } from "arktype";
|
|
2
|
+
import { and, asc, eq, inArray, isNull, lte, or, sql } from "drizzle-orm";
|
|
3
|
+
import { SidecarPlacementRequirement, sidecarAllocationStatuses, } from "@intx/types";
|
|
4
|
+
import { createWorkflowRunDispatchStore } from "./workflow-run-dispatch-store.js";
|
|
5
|
+
import { isLiveWorkflowRunStatus, liveWorkflowRunStatuses, principal, sidecar, sidecarAllocation, workflowRun, workflowRunLaunchSpec, } from "./schema/index.js";
|
|
6
|
+
const SidecarAllocationStatusValidator = type.enumerated(...sidecarAllocationStatuses);
|
|
7
|
+
const SidecarProvisionerApiVersion = type("1");
|
|
8
|
+
const activeStatuses = [
|
|
9
|
+
"pending",
|
|
10
|
+
"provisioning",
|
|
11
|
+
"allocated",
|
|
12
|
+
"replacing",
|
|
13
|
+
"releasing",
|
|
14
|
+
];
|
|
15
|
+
function parseSidecarAllocationRow(row) {
|
|
16
|
+
const placement = SidecarPlacementRequirement.assert({
|
|
17
|
+
sharing: row.placementSharing,
|
|
18
|
+
reuse: row.sidecarReuse,
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
id: row.id,
|
|
22
|
+
anchorRunId: row.anchorRunId,
|
|
23
|
+
tenantId: row.tenantId,
|
|
24
|
+
provisionerId: row.provisionerId,
|
|
25
|
+
provisionerApiVersion: SidecarProvisionerApiVersion.assert(row.provisionerApiVersion),
|
|
26
|
+
provisionerBindingFingerprint: row.provisionerBindingFingerprint,
|
|
27
|
+
...(row.sidecarId !== null ? { sidecarId: row.sidecarId } : {}),
|
|
28
|
+
placement,
|
|
29
|
+
status: SidecarAllocationStatusValidator.assert(row.status),
|
|
30
|
+
generation: row.generation,
|
|
31
|
+
...(row.ensureAcceptedGeneration !== null
|
|
32
|
+
? { ensureAcceptedGeneration: row.ensureAcceptedGeneration }
|
|
33
|
+
: {}),
|
|
34
|
+
...(row.externalRef !== null ? { externalRef: row.externalRef } : {}),
|
|
35
|
+
...(row.nextAttemptAt !== null ? { nextAttemptAt: row.nextAttemptAt } : {}),
|
|
36
|
+
...(row.reconciliationLeaseId !== null
|
|
37
|
+
? { reconciliationLeaseId: row.reconciliationLeaseId }
|
|
38
|
+
: {}),
|
|
39
|
+
...(row.reconciliationLeaseExpiresAt !== null
|
|
40
|
+
? { reconciliationLeaseExpiresAt: row.reconciliationLeaseExpiresAt }
|
|
41
|
+
: {}),
|
|
42
|
+
ensureAttempts: row.ensureAttempts,
|
|
43
|
+
destroyAttempts: row.destroyAttempts,
|
|
44
|
+
...(row.connectDeadline !== null
|
|
45
|
+
? { connectDeadline: row.connectDeadline }
|
|
46
|
+
: {}),
|
|
47
|
+
...(row.failureCode !== null ? { failureCode: row.failureCode } : {}),
|
|
48
|
+
...(row.failureMessage !== null
|
|
49
|
+
? { failureMessage: row.failureMessage }
|
|
50
|
+
: {}),
|
|
51
|
+
createdAt: row.createdAt,
|
|
52
|
+
updatedAt: row.updatedAt,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function databaseTimestamp(override) {
|
|
56
|
+
return override ?? sql `now()`;
|
|
57
|
+
}
|
|
58
|
+
function leaseCondition(expectedLeaseId) {
|
|
59
|
+
return expectedLeaseId === undefined
|
|
60
|
+
? []
|
|
61
|
+
: [eq(sidecarAllocation.reconciliationLeaseId, expectedLeaseId)];
|
|
62
|
+
}
|
|
63
|
+
export function createSidecarAllocationStore(db) {
|
|
64
|
+
const workflowRunDispatchStore = createWorkflowRunDispatchStore(db);
|
|
65
|
+
async function insertSidecarIdentity(tx, args) {
|
|
66
|
+
await tx.insert(sidecar).values({
|
|
67
|
+
id: args.sidecarId,
|
|
68
|
+
url: null,
|
|
69
|
+
tokenHashSha256: args.tokenHashSha256,
|
|
70
|
+
credentialScope: "allocated",
|
|
71
|
+
status: "offline",
|
|
72
|
+
createdAt: args.now,
|
|
73
|
+
updatedAt: args.now,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async function failRunningRuns(tx, anchorRunId, now) {
|
|
77
|
+
// Fail every live run anchored here -- both "running" runs and a "deployed"
|
|
78
|
+
// anchor torn down before its first trigger -- so a release settles them.
|
|
79
|
+
const failedRuns = await tx
|
|
80
|
+
.update(workflowRun)
|
|
81
|
+
.set({ status: "failed", endedAt: now })
|
|
82
|
+
.where(and(eq(workflowRun.anchorRunId, anchorRunId), inArray(workflowRun.status, [...liveWorkflowRunStatuses])))
|
|
83
|
+
.returning({ principalId: workflowRun.principalId });
|
|
84
|
+
const principalIds = failedRuns.flatMap(({ principalId }) => principalId === null ? [] : [principalId]);
|
|
85
|
+
if (principalIds.length > 0) {
|
|
86
|
+
await tx
|
|
87
|
+
.update(principal)
|
|
88
|
+
.set({ status: "deactivated", updatedAt: now })
|
|
89
|
+
.where(inArray(principal.id, principalIds));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async function beginRelease(args, tx) {
|
|
93
|
+
const now = databaseTimestamp(args.now);
|
|
94
|
+
const [updated] = await (tx ?? db)
|
|
95
|
+
.update(sidecarAllocation)
|
|
96
|
+
.set({
|
|
97
|
+
status: "releasing",
|
|
98
|
+
generation: args.expectedGeneration + 1,
|
|
99
|
+
nextAttemptAt: now,
|
|
100
|
+
reconciliationLeaseId: null,
|
|
101
|
+
reconciliationLeaseExpiresAt: null,
|
|
102
|
+
connectDeadline: null,
|
|
103
|
+
...(args.failureCode !== undefined
|
|
104
|
+
? { failureCode: args.failureCode }
|
|
105
|
+
: {}),
|
|
106
|
+
...(args.failureMessage !== undefined
|
|
107
|
+
? { failureMessage: args.failureMessage }
|
|
108
|
+
: {}),
|
|
109
|
+
updatedAt: now,
|
|
110
|
+
})
|
|
111
|
+
.where(and(eq(sidecarAllocation.id, args.allocationId), eq(sidecarAllocation.status, args.expectedStatus), eq(sidecarAllocation.generation, args.expectedGeneration), ...leaseCondition(args.expectedLeaseId)))
|
|
112
|
+
.returning();
|
|
113
|
+
return updated === undefined ? null : parseSidecarAllocationRow(updated);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
async createPending(args, tx) {
|
|
117
|
+
const executor = tx ?? db;
|
|
118
|
+
const [anchor] = await executor
|
|
119
|
+
.select({
|
|
120
|
+
tenantId: workflowRun.tenantId,
|
|
121
|
+
anchorRunId: workflowRun.anchorRunId,
|
|
122
|
+
status: workflowRun.status,
|
|
123
|
+
})
|
|
124
|
+
.from(workflowRun)
|
|
125
|
+
.where(eq(workflowRun.id, args.anchorRunId))
|
|
126
|
+
.limit(1);
|
|
127
|
+
if (anchor === undefined) {
|
|
128
|
+
throw new Error(`sidecarAllocationStore.createPending: anchor run ${args.anchorRunId} does not exist`);
|
|
129
|
+
}
|
|
130
|
+
if (anchor.tenantId !== args.tenantId ||
|
|
131
|
+
anchor.anchorRunId !== args.anchorRunId) {
|
|
132
|
+
throw new Error(`sidecarAllocationStore.createPending: run ${args.anchorRunId} is not an anchor for tenant ${args.tenantId}`);
|
|
133
|
+
}
|
|
134
|
+
if (!isLiveWorkflowRunStatus(anchor.status)) {
|
|
135
|
+
throw new Error(`sidecarAllocationStore.createPending: anchor run ${args.anchorRunId} is ${anchor.status}, expected a live run`);
|
|
136
|
+
}
|
|
137
|
+
const launchSpec = await executor.query.workflowRunLaunchSpec.findFirst({
|
|
138
|
+
columns: { anchorRunId: true },
|
|
139
|
+
where: eq(workflowRunLaunchSpec.anchorRunId, args.anchorRunId),
|
|
140
|
+
});
|
|
141
|
+
if (launchSpec === undefined) {
|
|
142
|
+
throw new Error(`sidecarAllocationStore.createPending: anchor run ${args.anchorRunId} has no launch specification`);
|
|
143
|
+
}
|
|
144
|
+
if (args.provisionerApiVersion !== 1) {
|
|
145
|
+
throw new Error("sidecarAllocationStore.createPending: unsupported API version");
|
|
146
|
+
}
|
|
147
|
+
const placement = SidecarPlacementRequirement.assert(args.placement ?? { sharing: "exclusive", reuse: "never" });
|
|
148
|
+
const now = databaseTimestamp(args.now);
|
|
149
|
+
const [inserted] = await executor
|
|
150
|
+
.insert(sidecarAllocation)
|
|
151
|
+
.values({
|
|
152
|
+
id: args.id,
|
|
153
|
+
anchorRunId: args.anchorRunId,
|
|
154
|
+
tenantId: args.tenantId,
|
|
155
|
+
provisionerId: args.provisionerId,
|
|
156
|
+
provisionerApiVersion: args.provisionerApiVersion,
|
|
157
|
+
provisionerBindingFingerprint: args.provisionerBindingFingerprint,
|
|
158
|
+
placementSharing: placement.sharing,
|
|
159
|
+
sidecarReuse: placement.reuse ?? "never",
|
|
160
|
+
status: "pending",
|
|
161
|
+
generation: 0,
|
|
162
|
+
nextAttemptAt: now,
|
|
163
|
+
createdAt: now,
|
|
164
|
+
updatedAt: now,
|
|
165
|
+
})
|
|
166
|
+
.returning();
|
|
167
|
+
if (inserted === undefined) {
|
|
168
|
+
throw new Error(`sidecarAllocationStore.createPending: insert returned no row for ${args.id}`);
|
|
169
|
+
}
|
|
170
|
+
return parseSidecarAllocationRow(inserted);
|
|
171
|
+
},
|
|
172
|
+
async bindInitialSidecar(args) {
|
|
173
|
+
return db.transaction(async (tx) => {
|
|
174
|
+
const [allocation] = await tx
|
|
175
|
+
.select()
|
|
176
|
+
.from(sidecarAllocation)
|
|
177
|
+
.where(eq(sidecarAllocation.id, args.allocationId))
|
|
178
|
+
.limit(1)
|
|
179
|
+
.for("update");
|
|
180
|
+
if (allocation === undefined ||
|
|
181
|
+
allocation.status !== "pending" ||
|
|
182
|
+
allocation.generation !== args.expectedGeneration ||
|
|
183
|
+
(args.expectedLeaseId !== undefined &&
|
|
184
|
+
allocation.reconciliationLeaseId !== args.expectedLeaseId)) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const now = databaseTimestamp(args.now);
|
|
188
|
+
await insertSidecarIdentity(tx, {
|
|
189
|
+
sidecarId: args.sidecarId,
|
|
190
|
+
tokenHashSha256: args.tokenHashSha256,
|
|
191
|
+
now,
|
|
192
|
+
});
|
|
193
|
+
const [updated] = await tx
|
|
194
|
+
.update(sidecarAllocation)
|
|
195
|
+
.set({
|
|
196
|
+
sidecarId: args.sidecarId,
|
|
197
|
+
status: "provisioning",
|
|
198
|
+
generation: args.expectedGeneration + 1,
|
|
199
|
+
ensureAcceptedGeneration: null,
|
|
200
|
+
externalRef: null,
|
|
201
|
+
connectDeadline: args.connectDeadline,
|
|
202
|
+
nextAttemptAt: now,
|
|
203
|
+
failureCode: null,
|
|
204
|
+
failureMessage: null,
|
|
205
|
+
updatedAt: now,
|
|
206
|
+
})
|
|
207
|
+
.where(and(eq(sidecarAllocation.id, args.allocationId), eq(sidecarAllocation.status, "pending"), eq(sidecarAllocation.generation, args.expectedGeneration), ...leaseCondition(args.expectedLeaseId)))
|
|
208
|
+
.returning();
|
|
209
|
+
if (updated === undefined) {
|
|
210
|
+
throw new Error(`sidecarAllocationStore.bindInitialSidecar: locked allocation ${args.allocationId} changed before update`);
|
|
211
|
+
}
|
|
212
|
+
return parseSidecarAllocationRow(updated);
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
async bindReplacementSidecar(args) {
|
|
216
|
+
return db.transaction(async (tx) => {
|
|
217
|
+
const [allocation] = await tx
|
|
218
|
+
.select()
|
|
219
|
+
.from(sidecarAllocation)
|
|
220
|
+
.where(eq(sidecarAllocation.id, args.allocationId))
|
|
221
|
+
.limit(1)
|
|
222
|
+
.for("update");
|
|
223
|
+
if (allocation === undefined ||
|
|
224
|
+
allocation.status !== "replacing" ||
|
|
225
|
+
allocation.generation !== args.generation ||
|
|
226
|
+
(args.expectedLeaseId !== undefined &&
|
|
227
|
+
allocation.reconciliationLeaseId !== args.expectedLeaseId)) {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
const now = databaseTimestamp(args.now);
|
|
231
|
+
await insertSidecarIdentity(tx, {
|
|
232
|
+
sidecarId: args.sidecarId,
|
|
233
|
+
tokenHashSha256: args.tokenHashSha256,
|
|
234
|
+
now,
|
|
235
|
+
});
|
|
236
|
+
const [updated] = await tx
|
|
237
|
+
.update(sidecarAllocation)
|
|
238
|
+
.set({
|
|
239
|
+
sidecarId: args.sidecarId,
|
|
240
|
+
status: "provisioning",
|
|
241
|
+
ensureAcceptedGeneration: null,
|
|
242
|
+
externalRef: null,
|
|
243
|
+
connectDeadline: args.connectDeadline,
|
|
244
|
+
nextAttemptAt: now,
|
|
245
|
+
destroyAttempts: sql `${sidecarAllocation.destroyAttempts} + 1`,
|
|
246
|
+
failureCode: null,
|
|
247
|
+
failureMessage: null,
|
|
248
|
+
updatedAt: now,
|
|
249
|
+
})
|
|
250
|
+
.where(and(eq(sidecarAllocation.id, args.allocationId), eq(sidecarAllocation.status, "replacing"), eq(sidecarAllocation.generation, args.generation), ...leaseCondition(args.expectedLeaseId)))
|
|
251
|
+
.returning();
|
|
252
|
+
if (updated === undefined) {
|
|
253
|
+
throw new Error(`sidecarAllocationStore.bindReplacementSidecar: locked allocation ${args.allocationId} changed before update`);
|
|
254
|
+
}
|
|
255
|
+
return parseSidecarAllocationRow(updated);
|
|
256
|
+
});
|
|
257
|
+
},
|
|
258
|
+
async markAllocated(args) {
|
|
259
|
+
const [updated] = await db
|
|
260
|
+
.update(sidecarAllocation)
|
|
261
|
+
.set({
|
|
262
|
+
status: "allocated",
|
|
263
|
+
ensureAcceptedGeneration: args.generation,
|
|
264
|
+
externalRef: args.externalRef ?? null,
|
|
265
|
+
nextAttemptAt: sidecarAllocation.connectDeadline,
|
|
266
|
+
ensureAttempts: sql `${sidecarAllocation.ensureAttempts} + 1`,
|
|
267
|
+
failureCode: null,
|
|
268
|
+
failureMessage: null,
|
|
269
|
+
updatedAt: databaseTimestamp(args.now),
|
|
270
|
+
})
|
|
271
|
+
.where(and(eq(sidecarAllocation.id, args.allocationId), eq(sidecarAllocation.status, "provisioning"), eq(sidecarAllocation.generation, args.generation), ...leaseCondition(args.expectedLeaseId)))
|
|
272
|
+
.returning();
|
|
273
|
+
return updated === undefined ? null : parseSidecarAllocationRow(updated);
|
|
274
|
+
},
|
|
275
|
+
async scheduleRetry(args) {
|
|
276
|
+
const [updated] = await db
|
|
277
|
+
.update(sidecarAllocation)
|
|
278
|
+
.set({
|
|
279
|
+
nextAttemptAt: args.nextAttemptAt,
|
|
280
|
+
reconciliationLeaseId: null,
|
|
281
|
+
reconciliationLeaseExpiresAt: null,
|
|
282
|
+
...(args.attempt === "ensure"
|
|
283
|
+
? { ensureAttempts: sql `${sidecarAllocation.ensureAttempts} + 1` }
|
|
284
|
+
: {}),
|
|
285
|
+
...(args.attempt === "destroy"
|
|
286
|
+
? { destroyAttempts: sql `${sidecarAllocation.destroyAttempts} + 1` }
|
|
287
|
+
: {}),
|
|
288
|
+
...(args.failure !== undefined
|
|
289
|
+
? {
|
|
290
|
+
failureCode: args.failure.code,
|
|
291
|
+
failureMessage: args.failure.message,
|
|
292
|
+
}
|
|
293
|
+
: {}),
|
|
294
|
+
updatedAt: databaseTimestamp(args.now),
|
|
295
|
+
})
|
|
296
|
+
.where(and(eq(sidecarAllocation.id, args.allocationId), eq(sidecarAllocation.status, args.expectedStatus), eq(sidecarAllocation.generation, args.expectedGeneration), ...leaseCondition(args.expectedLeaseId)))
|
|
297
|
+
.returning();
|
|
298
|
+
return updated === undefined ? null : parseSidecarAllocationRow(updated);
|
|
299
|
+
},
|
|
300
|
+
async beginReplacement(args) {
|
|
301
|
+
const now = databaseTimestamp(args.now);
|
|
302
|
+
return db.transaction(async (tx) => {
|
|
303
|
+
const [updated] = await tx
|
|
304
|
+
.update(sidecarAllocation)
|
|
305
|
+
.set({
|
|
306
|
+
status: "replacing",
|
|
307
|
+
generation: args.expectedGeneration + 1,
|
|
308
|
+
ensureAcceptedGeneration: null,
|
|
309
|
+
nextAttemptAt: args.nextAttemptAt,
|
|
310
|
+
reconciliationLeaseId: null,
|
|
311
|
+
reconciliationLeaseExpiresAt: null,
|
|
312
|
+
connectDeadline: null,
|
|
313
|
+
failureCode: args.failureCode,
|
|
314
|
+
failureMessage: args.failureMessage,
|
|
315
|
+
updatedAt: now,
|
|
316
|
+
})
|
|
317
|
+
.where(and(eq(sidecarAllocation.id, args.allocationId), eq(sidecarAllocation.status, args.expectedStatus), eq(sidecarAllocation.generation, args.expectedGeneration), ...leaseCondition(args.expectedLeaseId)))
|
|
318
|
+
.returning();
|
|
319
|
+
if (updated === undefined)
|
|
320
|
+
return null;
|
|
321
|
+
// The anchor public key is durable proof that this allocation
|
|
322
|
+
// generation completed restore and deployment. Clear it atomically
|
|
323
|
+
// with the generation advance so a replacement cannot mistake stale
|
|
324
|
+
// local sidecar state for a successfully restored workflow.
|
|
325
|
+
await tx
|
|
326
|
+
.update(workflowRun)
|
|
327
|
+
.set({ publicKey: null })
|
|
328
|
+
.where(eq(workflowRun.id, updated.anchorRunId));
|
|
329
|
+
return parseSidecarAllocationRow(updated);
|
|
330
|
+
});
|
|
331
|
+
},
|
|
332
|
+
beginRelease,
|
|
333
|
+
async beginUnrecoverableRelease(args) {
|
|
334
|
+
const now = databaseTimestamp(args.now);
|
|
335
|
+
return db.transaction(async (tx) => {
|
|
336
|
+
const releasing = await beginRelease({
|
|
337
|
+
...args,
|
|
338
|
+
expectedStatus: "allocated",
|
|
339
|
+
}, tx);
|
|
340
|
+
if (releasing === null)
|
|
341
|
+
return null;
|
|
342
|
+
await failRunningRuns(tx, releasing.anchorRunId, now);
|
|
343
|
+
await workflowRunDispatchStore.failUnsettled(releasing.anchorRunId, args.failureCode, args.failureMessage, now, tx);
|
|
344
|
+
return releasing;
|
|
345
|
+
});
|
|
346
|
+
},
|
|
347
|
+
async markReleased(args) {
|
|
348
|
+
const [updated] = await db
|
|
349
|
+
.update(sidecarAllocation)
|
|
350
|
+
.set({
|
|
351
|
+
status: "released",
|
|
352
|
+
nextAttemptAt: null,
|
|
353
|
+
reconciliationLeaseId: null,
|
|
354
|
+
reconciliationLeaseExpiresAt: null,
|
|
355
|
+
connectDeadline: null,
|
|
356
|
+
destroyAttempts: sql `${sidecarAllocation.destroyAttempts} + 1`,
|
|
357
|
+
updatedAt: databaseTimestamp(args.now),
|
|
358
|
+
})
|
|
359
|
+
.where(and(eq(sidecarAllocation.id, args.allocationId), eq(sidecarAllocation.status, "releasing"), eq(sidecarAllocation.generation, args.generation), ...leaseCondition(args.expectedLeaseId)))
|
|
360
|
+
.returning();
|
|
361
|
+
return updated === undefined ? null : parseSidecarAllocationRow(updated);
|
|
362
|
+
},
|
|
363
|
+
async failWithoutInfrastructure(args, tx) {
|
|
364
|
+
const now = databaseTimestamp(args.now);
|
|
365
|
+
const fail = async (executor) => {
|
|
366
|
+
const [updated] = await executor
|
|
367
|
+
.update(sidecarAllocation)
|
|
368
|
+
.set({
|
|
369
|
+
status: "failed",
|
|
370
|
+
failureCode: args.code,
|
|
371
|
+
failureMessage: args.message,
|
|
372
|
+
nextAttemptAt: null,
|
|
373
|
+
reconciliationLeaseId: null,
|
|
374
|
+
reconciliationLeaseExpiresAt: null,
|
|
375
|
+
connectDeadline: null,
|
|
376
|
+
updatedAt: now,
|
|
377
|
+
})
|
|
378
|
+
.where(and(eq(sidecarAllocation.id, args.allocationId), eq(sidecarAllocation.status, args.expectedStatus), eq(sidecarAllocation.generation, args.expectedGeneration), ...leaseCondition(args.expectedLeaseId)))
|
|
379
|
+
.returning();
|
|
380
|
+
if (updated === undefined)
|
|
381
|
+
return null;
|
|
382
|
+
await failRunningRuns(executor, updated.anchorRunId, now);
|
|
383
|
+
await workflowRunDispatchStore.failUnsettled(updated.anchorRunId, args.code, args.message, now, executor);
|
|
384
|
+
return parseSidecarAllocationRow(updated);
|
|
385
|
+
};
|
|
386
|
+
return tx === undefined ? db.transaction(fail) : fail(tx);
|
|
387
|
+
},
|
|
388
|
+
async findById(id) {
|
|
389
|
+
const row = await db.query.sidecarAllocation.findFirst({
|
|
390
|
+
where: eq(sidecarAllocation.id, id),
|
|
391
|
+
});
|
|
392
|
+
return row === undefined ? null : parseSidecarAllocationRow(row);
|
|
393
|
+
},
|
|
394
|
+
async findByAnchorRunId(anchorRunId) {
|
|
395
|
+
const row = await db.query.sidecarAllocation.findFirst({
|
|
396
|
+
where: eq(sidecarAllocation.anchorRunId, anchorRunId),
|
|
397
|
+
});
|
|
398
|
+
return row === undefined ? null : parseSidecarAllocationRow(row);
|
|
399
|
+
},
|
|
400
|
+
async claimNextReconcilable(args) {
|
|
401
|
+
return db.transaction(async (tx) => {
|
|
402
|
+
const [candidate] = await tx
|
|
403
|
+
.select({ id: sidecarAllocation.id })
|
|
404
|
+
.from(sidecarAllocation)
|
|
405
|
+
.where(and(inArray(sidecarAllocation.status, activeStatuses), lte(sidecarAllocation.nextAttemptAt, sql `now()`), or(isNull(sidecarAllocation.reconciliationLeaseExpiresAt), lte(sidecarAllocation.reconciliationLeaseExpiresAt, sql `now()`))))
|
|
406
|
+
.orderBy(asc(sidecarAllocation.nextAttemptAt), asc(sidecarAllocation.createdAt))
|
|
407
|
+
.limit(1)
|
|
408
|
+
.for("update", { skipLocked: true });
|
|
409
|
+
if (candidate === undefined)
|
|
410
|
+
return null;
|
|
411
|
+
const [claimed] = await tx
|
|
412
|
+
.update(sidecarAllocation)
|
|
413
|
+
.set({
|
|
414
|
+
reconciliationLeaseId: args.leaseId,
|
|
415
|
+
reconciliationLeaseExpiresAt: sql `now() + (${args.leaseDurationMs} * interval '1 millisecond')`,
|
|
416
|
+
})
|
|
417
|
+
.where(eq(sidecarAllocation.id, candidate.id))
|
|
418
|
+
.returning();
|
|
419
|
+
return claimed === undefined
|
|
420
|
+
? null
|
|
421
|
+
: parseSidecarAllocationRow(claimed);
|
|
422
|
+
});
|
|
423
|
+
},
|
|
424
|
+
async extendReconciliationLease(allocationId, leaseId, leaseDurationMs) {
|
|
425
|
+
const [updated] = await db
|
|
426
|
+
.update(sidecarAllocation)
|
|
427
|
+
.set({
|
|
428
|
+
reconciliationLeaseExpiresAt: sql `now() + (${leaseDurationMs} * interval '1 millisecond')`,
|
|
429
|
+
})
|
|
430
|
+
.where(and(eq(sidecarAllocation.id, allocationId), eq(sidecarAllocation.reconciliationLeaseId, leaseId)))
|
|
431
|
+
.returning({ id: sidecarAllocation.id });
|
|
432
|
+
return updated !== undefined;
|
|
433
|
+
},
|
|
434
|
+
async markConnectionReady(args) {
|
|
435
|
+
const [updated] = await db
|
|
436
|
+
.update(sidecarAllocation)
|
|
437
|
+
.set({
|
|
438
|
+
connectDeadline: null,
|
|
439
|
+
nextAttemptAt: null,
|
|
440
|
+
reconciliationLeaseId: null,
|
|
441
|
+
reconciliationLeaseExpiresAt: null,
|
|
442
|
+
failureCode: null,
|
|
443
|
+
failureMessage: null,
|
|
444
|
+
updatedAt: databaseTimestamp(args.now),
|
|
445
|
+
})
|
|
446
|
+
.where(and(eq(sidecarAllocation.id, args.allocationId), eq(sidecarAllocation.status, "allocated"), eq(sidecarAllocation.generation, args.generation), eq(sidecarAllocation.ensureAcceptedGeneration, args.generation), ...leaseCondition(args.expectedLeaseId)))
|
|
447
|
+
.returning();
|
|
448
|
+
return updated === undefined ? null : parseSidecarAllocationRow(updated);
|
|
449
|
+
},
|
|
450
|
+
async markConnectionLost(args) {
|
|
451
|
+
const [updated] = await db
|
|
452
|
+
.update(sidecarAllocation)
|
|
453
|
+
.set({
|
|
454
|
+
connectDeadline: args.connectDeadline,
|
|
455
|
+
nextAttemptAt: args.connectDeadline,
|
|
456
|
+
reconciliationLeaseId: null,
|
|
457
|
+
reconciliationLeaseExpiresAt: null,
|
|
458
|
+
updatedAt: databaseTimestamp(args.now),
|
|
459
|
+
})
|
|
460
|
+
.where(and(eq(sidecarAllocation.id, args.allocationId), eq(sidecarAllocation.status, "allocated"), eq(sidecarAllocation.generation, args.generation), eq(sidecarAllocation.ensureAcceptedGeneration, args.generation)))
|
|
461
|
+
.returning();
|
|
462
|
+
return updated === undefined ? null : parseSidecarAllocationRow(updated);
|
|
463
|
+
},
|
|
464
|
+
async scheduleReconnectIfUnscheduled(args) {
|
|
465
|
+
const connectDeadline = sql.param(args.connectDeadline, sidecarAllocation.connectDeadline);
|
|
466
|
+
const [updated] = await db
|
|
467
|
+
.update(sidecarAllocation)
|
|
468
|
+
.set({
|
|
469
|
+
connectDeadline: sql `coalesce(${sidecarAllocation.connectDeadline}, ${connectDeadline})`,
|
|
470
|
+
nextAttemptAt: sql `coalesce(${sidecarAllocation.connectDeadline}, ${connectDeadline})`,
|
|
471
|
+
updatedAt: databaseTimestamp(args.now),
|
|
472
|
+
})
|
|
473
|
+
.where(and(eq(sidecarAllocation.id, args.allocationId), eq(sidecarAllocation.status, "allocated"), eq(sidecarAllocation.generation, args.generation), eq(sidecarAllocation.ensureAcceptedGeneration, args.generation), isNull(sidecarAllocation.nextAttemptAt), isNull(sidecarAllocation.reconciliationLeaseId), isNull(sidecarAllocation.reconciliationLeaseExpiresAt)))
|
|
474
|
+
.returning();
|
|
475
|
+
return updated === undefined ? null : parseSidecarAllocationRow(updated);
|
|
476
|
+
},
|
|
477
|
+
async parkReconciliation(allocationId, leaseId, policy) {
|
|
478
|
+
const fallbackNextAttemptAt = policy.kind === "await-connection"
|
|
479
|
+
? policy.fallbackNextAttemptAt
|
|
480
|
+
: policy.notBefore;
|
|
481
|
+
const fallback = sql.param(fallbackNextAttemptAt, sidecarAllocation.nextAttemptAt);
|
|
482
|
+
const nextAttemptAt = policy.kind === "await-connection"
|
|
483
|
+
? sql `case when ${sidecarAllocation.connectDeadline} is null then ${fallback} else coalesce(${sidecarAllocation.nextAttemptAt}, ${sidecarAllocation.connectDeadline}) end`
|
|
484
|
+
: sql `greatest(coalesce(${sidecarAllocation.nextAttemptAt}, ${sidecarAllocation.connectDeadline}, ${fallback}), ${fallback})`;
|
|
485
|
+
const [updated] = await db
|
|
486
|
+
.update(sidecarAllocation)
|
|
487
|
+
.set({
|
|
488
|
+
nextAttemptAt,
|
|
489
|
+
reconciliationLeaseId: null,
|
|
490
|
+
reconciliationLeaseExpiresAt: null,
|
|
491
|
+
})
|
|
492
|
+
.where(and(eq(sidecarAllocation.id, allocationId), eq(sidecarAllocation.reconciliationLeaseId, leaseId)))
|
|
493
|
+
.returning({ id: sidecarAllocation.id });
|
|
494
|
+
return updated !== undefined;
|
|
495
|
+
},
|
|
496
|
+
async wakeReconciliation(allocationId, generation) {
|
|
497
|
+
const [updated] = await db
|
|
498
|
+
.update(sidecarAllocation)
|
|
499
|
+
.set({ nextAttemptAt: sql `now()` })
|
|
500
|
+
.where(and(eq(sidecarAllocation.id, allocationId), eq(sidecarAllocation.generation, generation), inArray(sidecarAllocation.status, activeStatuses)))
|
|
501
|
+
.returning({ id: sidecarAllocation.id });
|
|
502
|
+
return updated !== undefined;
|
|
503
|
+
},
|
|
504
|
+
async listActive() {
|
|
505
|
+
const rows = await db
|
|
506
|
+
.select()
|
|
507
|
+
.from(sidecarAllocation)
|
|
508
|
+
.where(inArray(sidecarAllocation.status, activeStatuses));
|
|
509
|
+
return rows.map(parseSidecarAllocationRow);
|
|
510
|
+
},
|
|
511
|
+
};
|
|
512
|
+
}
|