@cascade-flow/backend-postgres 0.2.5 → 0.2.8
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/db.d.ts +45 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +316 -43
- package/dist/index.js.map +4 -4
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -4744,6 +4744,7 @@ import {
|
|
|
4744
4744
|
projectRunStateFromEvents,
|
|
4745
4745
|
extractLogsFromEvents,
|
|
4746
4746
|
getCurrentAttemptNumber,
|
|
4747
|
+
getVersionIdFromEvents,
|
|
4747
4748
|
getMicrosecondTimestamp,
|
|
4748
4749
|
computeErrorAnalysis,
|
|
4749
4750
|
computeRetryAnalysis,
|
|
@@ -4773,6 +4774,10 @@ var esm_default = import_lib.default;
|
|
|
4773
4774
|
|
|
4774
4775
|
// src/db.ts
|
|
4775
4776
|
var { Pool: Pool2 } = esm_default;
|
|
4777
|
+
function stripEventIdFromJson(event) {
|
|
4778
|
+
const { eventId, ...eventWithoutId } = event;
|
|
4779
|
+
return eventWithoutId;
|
|
4780
|
+
}
|
|
4776
4781
|
|
|
4777
4782
|
class DatabaseClient {
|
|
4778
4783
|
pool;
|
|
@@ -4807,9 +4812,18 @@ class DatabaseClient {
|
|
|
4807
4812
|
} else if ("workflowAttemptNumber" in we) {
|
|
4808
4813
|
workflowAttemptNumber = we.workflowAttemptNumber;
|
|
4809
4814
|
}
|
|
4810
|
-
if (we.type === "WorkflowStarted") {
|
|
4815
|
+
if (we.type === "WorkflowStarted" || we.type === "WorkflowResumed") {
|
|
4811
4816
|
versionId = we.versionId;
|
|
4812
4817
|
}
|
|
4818
|
+
if (versionId === null) {
|
|
4819
|
+
const versionResult = await client.query(`SELECT version_id FROM ${this.schema}.workflow_events
|
|
4820
|
+
WHERE workflow_slug = $1 AND run_id = $2
|
|
4821
|
+
AND type IN ('WorkflowStarted', 'RunSubmitted')
|
|
4822
|
+
AND version_id IS NOT NULL
|
|
4823
|
+
ORDER BY timestamp_us DESC, event_id DESC
|
|
4824
|
+
LIMIT 1`, [we.workflowSlug, we.runId]);
|
|
4825
|
+
versionId = versionResult.rows[0]?.version_id ?? null;
|
|
4826
|
+
}
|
|
4813
4827
|
await client.query(`INSERT INTO ${this.schema}.workflow_events (
|
|
4814
4828
|
event_id, workflow_slug, run_id, timestamp_us, category, type, event_data,
|
|
4815
4829
|
workflow_attempt_number, available_at_us, priority, timeout_us, idempotency_key, version_id
|
|
@@ -4821,7 +4835,7 @@ class DatabaseClient {
|
|
|
4821
4835
|
we.timestampUs,
|
|
4822
4836
|
we.category,
|
|
4823
4837
|
we.type,
|
|
4824
|
-
JSON.stringify(event),
|
|
4838
|
+
JSON.stringify(stripEventIdFromJson(event)),
|
|
4825
4839
|
workflowAttemptNumber,
|
|
4826
4840
|
availableAtUs,
|
|
4827
4841
|
priority,
|
|
@@ -4860,7 +4874,10 @@ class DatabaseClient {
|
|
|
4860
4874
|
errorStackPortableHash = se.errorFingerprints.stackPortableHash;
|
|
4861
4875
|
}
|
|
4862
4876
|
const versionResult = await client.query(`SELECT version_id FROM ${this.schema}.workflow_events
|
|
4863
|
-
WHERE workflow_slug = $1 AND run_id = $2
|
|
4877
|
+
WHERE workflow_slug = $1 AND run_id = $2
|
|
4878
|
+
AND type IN ('WorkflowStarted', 'RunSubmitted')
|
|
4879
|
+
AND version_id IS NOT NULL
|
|
4880
|
+
ORDER BY timestamp_us DESC, event_id DESC
|
|
4864
4881
|
LIMIT 1`, [se.workflowSlug, se.runId]);
|
|
4865
4882
|
const versionId = versionResult.rows[0]?.version_id ?? null;
|
|
4866
4883
|
await client.query(`INSERT INTO ${this.schema}.step_events (
|
|
@@ -4877,7 +4894,7 @@ class DatabaseClient {
|
|
|
4877
4894
|
se.timestampUs,
|
|
4878
4895
|
se.category,
|
|
4879
4896
|
se.type,
|
|
4880
|
-
JSON.stringify(event),
|
|
4897
|
+
JSON.stringify(stripEventIdFromJson(event)),
|
|
4881
4898
|
workerId,
|
|
4882
4899
|
attemptNumber,
|
|
4883
4900
|
availableAtUs,
|
|
@@ -4915,6 +4932,15 @@ class DatabaseClient {
|
|
|
4915
4932
|
if (we.type === "WorkflowStarted") {
|
|
4916
4933
|
versionId = we.versionId;
|
|
4917
4934
|
}
|
|
4935
|
+
if (versionId === null) {
|
|
4936
|
+
const versionResult = await client.query(`SELECT version_id FROM ${this.schema}.workflow_events
|
|
4937
|
+
WHERE workflow_slug = $1 AND run_id = $2
|
|
4938
|
+
AND type IN ('WorkflowStarted', 'RunSubmitted')
|
|
4939
|
+
AND version_id IS NOT NULL
|
|
4940
|
+
ORDER BY timestamp_us DESC, event_id DESC
|
|
4941
|
+
LIMIT 1`, [we.workflowSlug, we.runId]);
|
|
4942
|
+
versionId = versionResult.rows[0]?.version_id ?? null;
|
|
4943
|
+
}
|
|
4918
4944
|
await client.query(`INSERT INTO ${this.schema}.workflow_events (
|
|
4919
4945
|
event_id, workflow_slug, run_id, timestamp_us, category, type, event_data,
|
|
4920
4946
|
workflow_attempt_number, available_at_us, priority, timeout_us, idempotency_key, version_id
|
|
@@ -4926,7 +4952,7 @@ class DatabaseClient {
|
|
|
4926
4952
|
we.timestampUs,
|
|
4927
4953
|
we.category,
|
|
4928
4954
|
we.type,
|
|
4929
|
-
JSON.stringify(event),
|
|
4955
|
+
JSON.stringify(stripEventIdFromJson(event)),
|
|
4930
4956
|
workflowAttemptNumber,
|
|
4931
4957
|
availableAtUs,
|
|
4932
4958
|
priority,
|
|
@@ -4965,7 +4991,10 @@ class DatabaseClient {
|
|
|
4965
4991
|
errorStackPortableHash = se.errorFingerprints.stackPortableHash;
|
|
4966
4992
|
}
|
|
4967
4993
|
const versionResult = await client.query(`SELECT version_id FROM ${this.schema}.workflow_events
|
|
4968
|
-
WHERE workflow_slug = $1 AND run_id = $2
|
|
4994
|
+
WHERE workflow_slug = $1 AND run_id = $2
|
|
4995
|
+
AND type IN ('WorkflowStarted', 'RunSubmitted')
|
|
4996
|
+
AND version_id IS NOT NULL
|
|
4997
|
+
ORDER BY timestamp_us DESC, event_id DESC
|
|
4969
4998
|
LIMIT 1`, [se.workflowSlug, se.runId]);
|
|
4970
4999
|
const versionId = versionResult.rows[0]?.version_id ?? null;
|
|
4971
5000
|
await client.query(`INSERT INTO ${this.schema}.step_events (
|
|
@@ -4982,7 +5011,7 @@ class DatabaseClient {
|
|
|
4982
5011
|
se.timestampUs,
|
|
4983
5012
|
se.category,
|
|
4984
5013
|
se.type,
|
|
4985
|
-
JSON.stringify(event),
|
|
5014
|
+
JSON.stringify(stripEventIdFromJson(event)),
|
|
4986
5015
|
workerId,
|
|
4987
5016
|
attemptNumber,
|
|
4988
5017
|
availableAtUs,
|
|
@@ -5024,12 +5053,12 @@ class DatabaseClient {
|
|
|
5024
5053
|
}
|
|
5025
5054
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
5026
5055
|
const query = `
|
|
5027
|
-
SELECT event_data FROM ${this.schema}.${table}
|
|
5056
|
+
SELECT event_data, event_id FROM ${this.schema}.${table}
|
|
5028
5057
|
${whereClause}
|
|
5029
5058
|
ORDER BY timestamp_us ASC, event_id ASC
|
|
5030
5059
|
`;
|
|
5031
5060
|
const result = await client.query(query, values);
|
|
5032
|
-
return result.rows.map((row) => row.event_data);
|
|
5061
|
+
return result.rows.map((row) => ({ ...row.event_data, eventId: row.event_id }));
|
|
5033
5062
|
} finally {
|
|
5034
5063
|
client.release();
|
|
5035
5064
|
}
|
|
@@ -5046,7 +5075,7 @@ class DatabaseClient {
|
|
|
5046
5075
|
ORDER BY timestamp_us ASC, event_id ASC
|
|
5047
5076
|
`;
|
|
5048
5077
|
const result = await client.query(query, [workflowSlug, runId]);
|
|
5049
|
-
return result.rows.map((row) => row.event_data);
|
|
5078
|
+
return result.rows.map((row) => ({ ...row.event_data, eventId: row.event_id }));
|
|
5050
5079
|
} finally {
|
|
5051
5080
|
client.release();
|
|
5052
5081
|
}
|
|
@@ -5090,13 +5119,20 @@ class DatabaseClient {
|
|
|
5090
5119
|
errorStackNormalizedHash = eventToWrite.errorFingerprints.stackNormalizedHash;
|
|
5091
5120
|
errorStackPortableHash = eventToWrite.errorFingerprints.stackPortableHash;
|
|
5092
5121
|
}
|
|
5122
|
+
const versionResult = await client.query(`SELECT version_id FROM ${this.schema}.workflow_events
|
|
5123
|
+
WHERE workflow_slug = $1 AND run_id = $2
|
|
5124
|
+
AND type IN ('WorkflowStarted', 'RunSubmitted')
|
|
5125
|
+
AND version_id IS NOT NULL
|
|
5126
|
+
ORDER BY timestamp_us DESC, event_id DESC
|
|
5127
|
+
LIMIT 1`, [eventToWrite.workflowSlug, eventToWrite.runId]);
|
|
5128
|
+
const versionId = versionResult.rows[0]?.version_id ?? null;
|
|
5093
5129
|
await client.query(`INSERT INTO ${this.schema}.step_events (
|
|
5094
5130
|
event_id, workflow_slug, run_id, step_id, timestamp_us, category, type, event_data,
|
|
5095
5131
|
worker_id, attempt_number, available_at_us, export_output,
|
|
5096
5132
|
error_name_hash, error_message_hash, error_stack_exact_hash,
|
|
5097
|
-
error_stack_normalized_hash, error_stack_portable_hash
|
|
5133
|
+
error_stack_normalized_hash, error_stack_portable_hash, version_id
|
|
5098
5134
|
)
|
|
5099
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)`, [
|
|
5135
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)`, [
|
|
5100
5136
|
eventToWrite.eventId,
|
|
5101
5137
|
eventToWrite.workflowSlug,
|
|
5102
5138
|
eventToWrite.runId,
|
|
@@ -5104,7 +5140,7 @@ class DatabaseClient {
|
|
|
5104
5140
|
eventToWrite.timestampUs,
|
|
5105
5141
|
eventToWrite.category,
|
|
5106
5142
|
eventToWrite.type,
|
|
5107
|
-
JSON.stringify(eventToWrite),
|
|
5143
|
+
JSON.stringify(stripEventIdFromJson(eventToWrite)),
|
|
5108
5144
|
workerId2,
|
|
5109
5145
|
attemptNumber,
|
|
5110
5146
|
null,
|
|
@@ -5113,7 +5149,8 @@ class DatabaseClient {
|
|
|
5113
5149
|
errorMessageHash,
|
|
5114
5150
|
errorStackExactHash,
|
|
5115
5151
|
errorStackNormalizedHash,
|
|
5116
|
-
errorStackPortableHash
|
|
5152
|
+
errorStackPortableHash,
|
|
5153
|
+
versionId
|
|
5117
5154
|
]);
|
|
5118
5155
|
await client.query("COMMIT");
|
|
5119
5156
|
return true;
|
|
@@ -5309,6 +5346,59 @@ class DatabaseClient {
|
|
|
5309
5346
|
client.release();
|
|
5310
5347
|
}
|
|
5311
5348
|
}
|
|
5349
|
+
async getWorkflowVersion(workflowSlug, versionId) {
|
|
5350
|
+
const client = await this.pool.connect();
|
|
5351
|
+
try {
|
|
5352
|
+
const result = await client.query(`WITH numbered_versions AS (
|
|
5353
|
+
SELECT *,
|
|
5354
|
+
ROW_NUMBER() OVER (PARTITION BY workflow_slug ORDER BY created_at ASC) as version_number
|
|
5355
|
+
FROM ${this.schema}.workflow_versions
|
|
5356
|
+
WHERE workflow_slug = $1
|
|
5357
|
+
)
|
|
5358
|
+
SELECT * FROM numbered_versions WHERE version_id = $2`, [workflowSlug, versionId]);
|
|
5359
|
+
if (result.rows.length === 0)
|
|
5360
|
+
return null;
|
|
5361
|
+
return result.rows[0];
|
|
5362
|
+
} finally {
|
|
5363
|
+
client.release();
|
|
5364
|
+
}
|
|
5365
|
+
}
|
|
5366
|
+
async getCurrentWorkflowVersion(workflowSlug) {
|
|
5367
|
+
const client = await this.pool.connect();
|
|
5368
|
+
try {
|
|
5369
|
+
const result = await client.query(`WITH numbered_versions AS (
|
|
5370
|
+
SELECT *,
|
|
5371
|
+
ROW_NUMBER() OVER (PARTITION BY workflow_slug ORDER BY created_at ASC) as version_number
|
|
5372
|
+
FROM ${this.schema}.workflow_versions
|
|
5373
|
+
WHERE workflow_slug = $1
|
|
5374
|
+
)
|
|
5375
|
+
SELECT * FROM numbered_versions
|
|
5376
|
+
ORDER BY created_at DESC
|
|
5377
|
+
LIMIT 1`, [workflowSlug]);
|
|
5378
|
+
if (result.rows.length === 0)
|
|
5379
|
+
return null;
|
|
5380
|
+
return result.rows[0];
|
|
5381
|
+
} finally {
|
|
5382
|
+
client.release();
|
|
5383
|
+
}
|
|
5384
|
+
}
|
|
5385
|
+
async listWorkflowVersions(workflowSlug, limit) {
|
|
5386
|
+
const client = await this.pool.connect();
|
|
5387
|
+
try {
|
|
5388
|
+
const result = await client.query(`WITH numbered_versions AS (
|
|
5389
|
+
SELECT *,
|
|
5390
|
+
ROW_NUMBER() OVER (PARTITION BY workflow_slug ORDER BY created_at ASC) as version_number
|
|
5391
|
+
FROM ${this.schema}.workflow_versions
|
|
5392
|
+
WHERE workflow_slug = $1
|
|
5393
|
+
)
|
|
5394
|
+
SELECT * FROM numbered_versions
|
|
5395
|
+
ORDER BY created_at DESC
|
|
5396
|
+
LIMIT $2`, [workflowSlug, limit]);
|
|
5397
|
+
return result.rows;
|
|
5398
|
+
} finally {
|
|
5399
|
+
client.release();
|
|
5400
|
+
}
|
|
5401
|
+
}
|
|
5312
5402
|
async saveIdempotencyKey(hash, runId) {
|
|
5313
5403
|
const client = await this.pool.connect();
|
|
5314
5404
|
try {
|
|
@@ -5734,6 +5824,200 @@ class PostgresBackend extends Backend {
|
|
|
5734
5824
|
return this.db.loadAllRunEvents(workflowSlug, runId);
|
|
5735
5825
|
}
|
|
5736
5826
|
}
|
|
5827
|
+
async copyEntireRun(workflowSlug, sourceRunId, targetRunId) {
|
|
5828
|
+
await this.copyEntireRunWithClient(workflowSlug, sourceRunId, targetRunId, this.db.getPool());
|
|
5829
|
+
}
|
|
5830
|
+
async copyEntireRunWithClient(workflowSlug, sourceRunId, targetRunId, client) {
|
|
5831
|
+
const schema = this.db.getSchema();
|
|
5832
|
+
await client.query(`INSERT INTO ${schema}.workflow_events (
|
|
5833
|
+
event_id, workflow_slug, run_id, timestamp_us, category, type, event_data, created_at,
|
|
5834
|
+
workflow_attempt_number, available_at_us, priority, timeout_us, idempotency_key, version_id
|
|
5835
|
+
)
|
|
5836
|
+
SELECT
|
|
5837
|
+
gen_random_uuid()::text,
|
|
5838
|
+
workflow_slug,
|
|
5839
|
+
$2,
|
|
5840
|
+
timestamp_us,
|
|
5841
|
+
category,
|
|
5842
|
+
type,
|
|
5843
|
+
jsonb_set(event_data, '{runId}', to_jsonb($2::text)),
|
|
5844
|
+
created_at,
|
|
5845
|
+
workflow_attempt_number,
|
|
5846
|
+
available_at_us,
|
|
5847
|
+
priority,
|
|
5848
|
+
timeout_us,
|
|
5849
|
+
idempotency_key,
|
|
5850
|
+
version_id
|
|
5851
|
+
FROM ${schema}.workflow_events
|
|
5852
|
+
WHERE workflow_slug = $1 AND run_id = $3`, [workflowSlug, targetRunId, sourceRunId]);
|
|
5853
|
+
await client.query(`INSERT INTO ${schema}.step_events (
|
|
5854
|
+
event_id, workflow_slug, run_id, step_id, timestamp_us, category, type, event_data, created_at,
|
|
5855
|
+
worker_id, attempt_number, available_at_us, export_output,
|
|
5856
|
+
error_name_hash, error_message_hash, error_stack_exact_hash, error_stack_normalized_hash, error_stack_portable_hash,
|
|
5857
|
+
version_id
|
|
5858
|
+
)
|
|
5859
|
+
SELECT
|
|
5860
|
+
gen_random_uuid()::text,
|
|
5861
|
+
workflow_slug,
|
|
5862
|
+
$2,
|
|
5863
|
+
step_id,
|
|
5864
|
+
timestamp_us,
|
|
5865
|
+
category,
|
|
5866
|
+
type,
|
|
5867
|
+
jsonb_set(event_data, '{runId}', to_jsonb($2::text)),
|
|
5868
|
+
created_at,
|
|
5869
|
+
worker_id,
|
|
5870
|
+
attempt_number,
|
|
5871
|
+
available_at_us,
|
|
5872
|
+
export_output,
|
|
5873
|
+
error_name_hash,
|
|
5874
|
+
error_message_hash,
|
|
5875
|
+
error_stack_exact_hash,
|
|
5876
|
+
error_stack_normalized_hash,
|
|
5877
|
+
error_stack_portable_hash,
|
|
5878
|
+
version_id
|
|
5879
|
+
FROM ${schema}.step_events
|
|
5880
|
+
WHERE workflow_slug = $1 AND run_id = $3`, [workflowSlug, targetRunId, sourceRunId]);
|
|
5881
|
+
}
|
|
5882
|
+
async deleteStepEvents(workflowSlug, runId, stepIds) {
|
|
5883
|
+
await this.deleteStepEventsWithClient(workflowSlug, runId, stepIds, this.db.getPool());
|
|
5884
|
+
}
|
|
5885
|
+
async deleteStepEventsWithClient(workflowSlug, runId, stepIds, client) {
|
|
5886
|
+
if (stepIds.size === 0)
|
|
5887
|
+
return;
|
|
5888
|
+
const schema = this.db.getSchema();
|
|
5889
|
+
const stepIdsArray = Array.from(stepIds);
|
|
5890
|
+
await client.query(`DELETE FROM ${schema}.step_events
|
|
5891
|
+
WHERE workflow_slug = $1 AND run_id = $2 AND step_id = ANY($3)`, [workflowSlug, runId, stepIdsArray]);
|
|
5892
|
+
}
|
|
5893
|
+
async deleteWorkflowTerminalEvents(workflowSlug, runId) {
|
|
5894
|
+
await this.deleteWorkflowTerminalEventsWithClient(workflowSlug, runId, this.db.getPool());
|
|
5895
|
+
}
|
|
5896
|
+
async deleteWorkflowTerminalEventsWithClient(workflowSlug, runId, client) {
|
|
5897
|
+
const schema = this.db.getSchema();
|
|
5898
|
+
await client.query(`DELETE FROM ${schema}.workflow_events
|
|
5899
|
+
WHERE workflow_slug = $1
|
|
5900
|
+
AND run_id = $2
|
|
5901
|
+
AND type IN ('WorkflowCompleted', 'WorkflowFailed', 'WorkflowCancelled')`, [workflowSlug, runId]);
|
|
5902
|
+
}
|
|
5903
|
+
async copyWorkflowEvents(workflowSlug, sourceRunId, targetRunId, excludeTerminal) {
|
|
5904
|
+
const pool = this.db.getPool();
|
|
5905
|
+
const schema = this.db.getSchema();
|
|
5906
|
+
const terminalFilter = excludeTerminal ? `AND type NOT IN ('WorkflowCompleted', 'WorkflowFailed', 'WorkflowCancelled')` : "";
|
|
5907
|
+
await pool.query(`INSERT INTO ${schema}.workflow_events (
|
|
5908
|
+
event_id, workflow_slug, run_id, timestamp_us, category, type, event_data, created_at,
|
|
5909
|
+
workflow_attempt_number, available_at_us, priority, timeout_us, idempotency_key, version_id
|
|
5910
|
+
)
|
|
5911
|
+
SELECT
|
|
5912
|
+
gen_random_uuid()::text,
|
|
5913
|
+
workflow_slug,
|
|
5914
|
+
$3,
|
|
5915
|
+
timestamp_us,
|
|
5916
|
+
category,
|
|
5917
|
+
type,
|
|
5918
|
+
jsonb_set(event_data, '{runId}', to_jsonb($3::text)),
|
|
5919
|
+
created_at,
|
|
5920
|
+
workflow_attempt_number,
|
|
5921
|
+
available_at_us,
|
|
5922
|
+
priority,
|
|
5923
|
+
timeout_us,
|
|
5924
|
+
idempotency_key,
|
|
5925
|
+
version_id
|
|
5926
|
+
FROM ${schema}.workflow_events
|
|
5927
|
+
WHERE workflow_slug = $1
|
|
5928
|
+
AND run_id = $2
|
|
5929
|
+
${terminalFilter}`, [workflowSlug, sourceRunId, targetRunId]);
|
|
5930
|
+
}
|
|
5931
|
+
async copyStepEvents(workflowSlug, sourceRunId, targetRunId, includeStepIds) {
|
|
5932
|
+
const pool = this.db.getPool();
|
|
5933
|
+
const schema = this.db.getSchema();
|
|
5934
|
+
const stepIdsArray = Array.from(includeStepIds);
|
|
5935
|
+
if (stepIdsArray.length === 0)
|
|
5936
|
+
return;
|
|
5937
|
+
await pool.query(`INSERT INTO ${schema}.step_events (
|
|
5938
|
+
event_id, workflow_slug, run_id, step_id, timestamp_us, category, type, event_data, created_at,
|
|
5939
|
+
worker_id, attempt_number, available_at_us, export_output,
|
|
5940
|
+
error_name_hash, error_message_hash, error_stack_exact_hash, error_stack_normalized_hash, error_stack_portable_hash,
|
|
5941
|
+
version_id
|
|
5942
|
+
)
|
|
5943
|
+
SELECT
|
|
5944
|
+
gen_random_uuid()::text,
|
|
5945
|
+
workflow_slug,
|
|
5946
|
+
$3,
|
|
5947
|
+
step_id,
|
|
5948
|
+
timestamp_us,
|
|
5949
|
+
category,
|
|
5950
|
+
type,
|
|
5951
|
+
jsonb_set(event_data, '{runId}', to_jsonb($3::text)),
|
|
5952
|
+
created_at,
|
|
5953
|
+
worker_id,
|
|
5954
|
+
attempt_number,
|
|
5955
|
+
available_at_us,
|
|
5956
|
+
export_output,
|
|
5957
|
+
error_name_hash,
|
|
5958
|
+
error_message_hash,
|
|
5959
|
+
error_stack_exact_hash,
|
|
5960
|
+
error_stack_normalized_hash,
|
|
5961
|
+
error_stack_portable_hash,
|
|
5962
|
+
version_id
|
|
5963
|
+
FROM ${schema}.step_events
|
|
5964
|
+
WHERE workflow_slug = $1
|
|
5965
|
+
AND run_id = $2
|
|
5966
|
+
AND step_id = ANY($4)`, [workflowSlug, sourceRunId, targetRunId, stepIdsArray]);
|
|
5967
|
+
}
|
|
5968
|
+
async rerunFrom(params) {
|
|
5969
|
+
const parentRun = await this.getRun(params.parentRunId);
|
|
5970
|
+
if (!parentRun) {
|
|
5971
|
+
throw new Error(`Parent run "${params.parentRunId}" not found`);
|
|
5972
|
+
}
|
|
5973
|
+
const dependents = await this.calculateDependents(parentRun.workflowSlug, params.fromStepId);
|
|
5974
|
+
const rerunStepIds = new Set([params.fromStepId, ...dependents]);
|
|
5975
|
+
const newRunId = getMicrosecondTimestamp().toString();
|
|
5976
|
+
const pool = this.db.getPool();
|
|
5977
|
+
const client = await pool.connect();
|
|
5978
|
+
try {
|
|
5979
|
+
await client.query("BEGIN");
|
|
5980
|
+
await this.copyEntireRunWithClient(parentRun.workflowSlug, params.parentRunId, newRunId, client);
|
|
5981
|
+
await this.deleteStepEventsWithClient(parentRun.workflowSlug, newRunId, rerunStepIds, client);
|
|
5982
|
+
await this.deleteWorkflowTerminalEventsWithClient(parentRun.workflowSlug, newRunId, client);
|
|
5983
|
+
await client.query("COMMIT");
|
|
5984
|
+
} catch (error) {
|
|
5985
|
+
await client.query("ROLLBACK");
|
|
5986
|
+
throw error;
|
|
5987
|
+
} finally {
|
|
5988
|
+
client.release();
|
|
5989
|
+
}
|
|
5990
|
+
const currentVersion = await this.getCurrentWorkflowVersion(parentRun.workflowSlug);
|
|
5991
|
+
if (!currentVersion) {
|
|
5992
|
+
throw new Error(`Workflow ${parentRun.workflowSlug} not registered. Please ensure the worker has started and registered workflows.`);
|
|
5993
|
+
}
|
|
5994
|
+
const parentWorkflowEvents = await this.loadEvents(parentRun.workflowSlug, params.parentRunId, {
|
|
5995
|
+
category: "workflow"
|
|
5996
|
+
});
|
|
5997
|
+
const parentVersionId = getVersionIdFromEvents(parentWorkflowEvents);
|
|
5998
|
+
const timestamp = getMicrosecondTimestamp();
|
|
5999
|
+
await this.appendEvent(parentRun.workflowSlug, newRunId, {
|
|
6000
|
+
category: "workflow",
|
|
6001
|
+
type: "WorkflowRerunFromStep",
|
|
6002
|
+
eventId: this.generateEventId(timestamp),
|
|
6003
|
+
timestampUs: timestamp,
|
|
6004
|
+
workflowSlug: parentRun.workflowSlug,
|
|
6005
|
+
runId: newRunId,
|
|
6006
|
+
parentRunId: params.parentRunId,
|
|
6007
|
+
rerunFromStepId: params.fromStepId,
|
|
6008
|
+
rerunStepIds: Array.from(rerunStepIds),
|
|
6009
|
+
versionId: currentVersion.versionId,
|
|
6010
|
+
parentVersionId
|
|
6011
|
+
});
|
|
6012
|
+
await this.submitRun({
|
|
6013
|
+
workflowSlug: parentRun.workflowSlug,
|
|
6014
|
+
runId: newRunId,
|
|
6015
|
+
input: params.input
|
|
6016
|
+
});
|
|
6017
|
+
return {
|
|
6018
|
+
runId: newRunId
|
|
6019
|
+
};
|
|
6020
|
+
}
|
|
5737
6021
|
async saveStepScheduled(workflowSlug, runId, stepId, metadata) {
|
|
5738
6022
|
const now = getMicrosecondTimestamp();
|
|
5739
6023
|
const event = {
|
|
@@ -6025,6 +6309,7 @@ class PostgresBackend extends Backend {
|
|
|
6025
6309
|
timestampUs: timestamp,
|
|
6026
6310
|
workflowSlug,
|
|
6027
6311
|
runId,
|
|
6312
|
+
versionId: metadata.versionId,
|
|
6028
6313
|
originalRunId: metadata.originalRunId,
|
|
6029
6314
|
resumedSteps: metadata.resumedSteps,
|
|
6030
6315
|
pendingSteps: metadata.pendingSteps
|
|
@@ -6327,20 +6612,17 @@ class PostgresBackend extends Backend {
|
|
|
6327
6612
|
]);
|
|
6328
6613
|
}
|
|
6329
6614
|
async getWorkflowVersion(workflowSlug, versionId) {
|
|
6330
|
-
const
|
|
6331
|
-
|
|
6332
|
-
WHERE workflow_slug = $1 AND version_id = $2
|
|
6333
|
-
`, [workflowSlug, versionId]);
|
|
6334
|
-
if (result.rows.length === 0)
|
|
6615
|
+
const row = await this.db.getWorkflowVersion(workflowSlug, versionId);
|
|
6616
|
+
if (!row)
|
|
6335
6617
|
return null;
|
|
6336
|
-
const row = result.rows[0];
|
|
6337
6618
|
return {
|
|
6338
6619
|
workflowSlug: row.workflow_slug,
|
|
6339
6620
|
versionId: row.version_id,
|
|
6621
|
+
versionNumber: parseInt(row.version_number.toString(), 10),
|
|
6340
6622
|
createdAt: Math.floor(new Date(row.created_at).getTime() * 1000),
|
|
6341
6623
|
stepManifest: row.step_manifest,
|
|
6342
6624
|
totalSteps: row.total_steps,
|
|
6343
|
-
git: row.git_commit ? {
|
|
6625
|
+
git: row.git_commit && row.git_dirty !== null && row.git_branch !== null ? {
|
|
6344
6626
|
commit: row.git_commit,
|
|
6345
6627
|
dirty: row.git_dirty,
|
|
6346
6628
|
branch: row.git_branch
|
|
@@ -6348,22 +6630,17 @@ class PostgresBackend extends Backend {
|
|
|
6348
6630
|
};
|
|
6349
6631
|
}
|
|
6350
6632
|
async getCurrentWorkflowVersion(workflowSlug) {
|
|
6351
|
-
const
|
|
6352
|
-
|
|
6353
|
-
WHERE workflow_slug = $1
|
|
6354
|
-
ORDER BY created_at DESC
|
|
6355
|
-
LIMIT 1
|
|
6356
|
-
`, [workflowSlug]);
|
|
6357
|
-
if (result.rows.length === 0)
|
|
6633
|
+
const row = await this.db.getCurrentWorkflowVersion(workflowSlug);
|
|
6634
|
+
if (!row)
|
|
6358
6635
|
return null;
|
|
6359
|
-
const row = result.rows[0];
|
|
6360
6636
|
return {
|
|
6361
6637
|
workflowSlug: row.workflow_slug,
|
|
6362
6638
|
versionId: row.version_id,
|
|
6639
|
+
versionNumber: parseInt(row.version_number.toString(), 10),
|
|
6363
6640
|
createdAt: Math.floor(new Date(row.created_at).getTime() * 1000),
|
|
6364
6641
|
stepManifest: row.step_manifest,
|
|
6365
6642
|
totalSteps: row.total_steps,
|
|
6366
|
-
git: row.git_commit ? {
|
|
6643
|
+
git: row.git_commit && row.git_dirty !== null && row.git_branch !== null ? {
|
|
6367
6644
|
commit: row.git_commit,
|
|
6368
6645
|
dirty: row.git_dirty,
|
|
6369
6646
|
branch: row.git_branch
|
|
@@ -6372,19 +6649,15 @@ class PostgresBackend extends Backend {
|
|
|
6372
6649
|
}
|
|
6373
6650
|
async listWorkflowVersions(workflowSlug, options) {
|
|
6374
6651
|
const limit = options?.limit ?? 100;
|
|
6375
|
-
const
|
|
6376
|
-
|
|
6377
|
-
WHERE workflow_slug = $1
|
|
6378
|
-
ORDER BY created_at DESC
|
|
6379
|
-
LIMIT $2
|
|
6380
|
-
`, [workflowSlug, limit]);
|
|
6381
|
-
return result.rows.map((row) => ({
|
|
6652
|
+
const rows = await this.db.listWorkflowVersions(workflowSlug, limit);
|
|
6653
|
+
return rows.map((row) => ({
|
|
6382
6654
|
workflowSlug: row.workflow_slug,
|
|
6383
6655
|
versionId: row.version_id,
|
|
6656
|
+
versionNumber: parseInt(row.version_number.toString(), 10),
|
|
6384
6657
|
createdAt: Math.floor(new Date(row.created_at).getTime() * 1000),
|
|
6385
6658
|
stepManifest: row.step_manifest,
|
|
6386
6659
|
totalSteps: row.total_steps,
|
|
6387
|
-
git: row.git_commit ? {
|
|
6660
|
+
git: row.git_commit && row.git_dirty !== null && row.git_branch !== null ? {
|
|
6388
6661
|
commit: row.git_commit,
|
|
6389
6662
|
dirty: row.git_dirty,
|
|
6390
6663
|
branch: row.git_branch
|
|
@@ -6399,7 +6672,7 @@ class PostgresBackend extends Backend {
|
|
|
6399
6672
|
const startUs = options?.startUs ?? now - 24 * 60 * 60 * 1000 * 1000;
|
|
6400
6673
|
const endUs = options?.endUs ?? now;
|
|
6401
6674
|
let stepQuery = `
|
|
6402
|
-
SELECT event_data
|
|
6675
|
+
SELECT event_data, event_id
|
|
6403
6676
|
FROM ${this.db.getSchema()}.step_events
|
|
6404
6677
|
WHERE timestamp_us >= $1 AND timestamp_us <= $2
|
|
6405
6678
|
`;
|
|
@@ -6423,7 +6696,7 @@ class PostgresBackend extends Backend {
|
|
|
6423
6696
|
}
|
|
6424
6697
|
stepQuery += ` ORDER BY timestamp_us ASC`;
|
|
6425
6698
|
let workflowQuery = `
|
|
6426
|
-
SELECT event_data
|
|
6699
|
+
SELECT event_data, event_id
|
|
6427
6700
|
FROM ${this.db.getSchema()}.workflow_events
|
|
6428
6701
|
WHERE timestamp_us >= $1 AND timestamp_us <= $2
|
|
6429
6702
|
`;
|
|
@@ -6445,8 +6718,8 @@ class PostgresBackend extends Backend {
|
|
|
6445
6718
|
this.db.getPool().query(stepQuery, stepParams),
|
|
6446
6719
|
options?.stepId ? Promise.resolve({ rows: [] }) : this.db.getPool().query(workflowQuery, workflowParams)
|
|
6447
6720
|
]);
|
|
6448
|
-
const stepEvents = stepResult.rows.map((row) => row.event_data);
|
|
6449
|
-
const workflowEvents = workflowResult.rows.map((row) => row.event_data);
|
|
6721
|
+
const stepEvents = stepResult.rows.map((row) => ({ ...row.event_data, eventId: row.event_id }));
|
|
6722
|
+
const workflowEvents = workflowResult.rows.map((row) => ({ ...row.event_data, eventId: row.event_id }));
|
|
6450
6723
|
return { stepEvents, workflowEvents };
|
|
6451
6724
|
}
|
|
6452
6725
|
async getErrorAnalysis(options) {
|
|
@@ -6793,4 +7066,4 @@ export {
|
|
|
6793
7066
|
PostgresBackend
|
|
6794
7067
|
};
|
|
6795
7068
|
|
|
6796
|
-
//# debugId=
|
|
7069
|
+
//# debugId=53B1DE663ECDB0B364756E2164756E21
|