@pgflow/core 0.0.5-prealpha.2
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.md +660 -0
- package/README.md +373 -0
- package/__tests__/mocks/index.ts +1 -0
- package/__tests__/mocks/postgres.ts +37 -0
- package/__tests__/types/PgflowSqlClient.test-d.ts +59 -0
- package/dist/LICENSE.md +660 -0
- package/dist/README.md +373 -0
- package/dist/index.js +54 -0
- package/docs/options_for_flow_and_steps.md +75 -0
- package/docs/pgflow-blob-reference-system.md +179 -0
- package/eslint.config.cjs +22 -0
- package/example-flow.mermaid +5 -0
- package/example-flow.svg +1 -0
- package/flow-lifecycle.mermaid +83 -0
- package/flow-lifecycle.svg +1 -0
- package/out-tsc/vitest/__tests__/mocks/index.d.ts +2 -0
- package/out-tsc/vitest/__tests__/mocks/index.d.ts.map +1 -0
- package/out-tsc/vitest/__tests__/mocks/postgres.d.ts +15 -0
- package/out-tsc/vitest/__tests__/mocks/postgres.d.ts.map +1 -0
- package/out-tsc/vitest/__tests__/types/PgflowSqlClient.test-d.d.ts +2 -0
- package/out-tsc/vitest/__tests__/types/PgflowSqlClient.test-d.d.ts.map +1 -0
- package/out-tsc/vitest/tsconfig.spec.tsbuildinfo +1 -0
- package/out-tsc/vitest/vite.config.d.ts +3 -0
- package/out-tsc/vitest/vite.config.d.ts.map +1 -0
- package/package.json +28 -0
- package/pkgs/core/dist/index.js +54 -0
- package/pkgs/core/dist/pkgs/core/LICENSE.md +660 -0
- package/pkgs/core/dist/pkgs/core/README.md +373 -0
- package/pkgs/dsl/dist/index.js +123 -0
- package/pkgs/dsl/dist/pkgs/dsl/README.md +11 -0
- package/project.json +125 -0
- package/prompts/architect.md +87 -0
- package/prompts/condition.md +33 -0
- package/prompts/declarative_sql.md +15 -0
- package/prompts/deps_in_payloads.md +20 -0
- package/prompts/dsl-multi-arg.ts +48 -0
- package/prompts/dsl-options.md +39 -0
- package/prompts/dsl-single-arg.ts +51 -0
- package/prompts/dsl-two-arg.ts +61 -0
- package/prompts/dsl.md +119 -0
- package/prompts/fanout_steps.md +1 -0
- package/prompts/json_schemas.md +36 -0
- package/prompts/one_shot.md +286 -0
- package/prompts/pgtap.md +229 -0
- package/prompts/sdk.md +59 -0
- package/prompts/step_types.md +62 -0
- package/prompts/versioning.md +16 -0
- package/queries/fail_permanently.sql +17 -0
- package/queries/fail_task.sql +21 -0
- package/queries/sequential.sql +47 -0
- package/queries/two_roots_left_right.sql +59 -0
- package/schema.svg +1 -0
- package/scripts/colorize-pgtap-output.awk +72 -0
- package/scripts/run-test-with-colors +5 -0
- package/scripts/watch-test +7 -0
- package/src/PgflowSqlClient.ts +85 -0
- package/src/database-types.ts +759 -0
- package/src/index.ts +3 -0
- package/src/types.ts +103 -0
- package/supabase/config.toml +32 -0
- package/supabase/migrations/000000_schema.sql +150 -0
- package/supabase/migrations/000005_create_flow.sql +29 -0
- package/supabase/migrations/000010_add_step.sql +48 -0
- package/supabase/migrations/000015_start_ready_steps.sql +45 -0
- package/supabase/migrations/000020_start_flow.sql +46 -0
- package/supabase/migrations/000030_read_with_poll_backport.sql +70 -0
- package/supabase/migrations/000040_poll_for_tasks.sql +100 -0
- package/supabase/migrations/000045_maybe_complete_run.sql +30 -0
- package/supabase/migrations/000050_complete_task.sql +98 -0
- package/supabase/migrations/000055_calculate_retry_delay.sql +11 -0
- package/supabase/migrations/000060_fail_task.sql +124 -0
- package/supabase/migrations/000_edge_worker_initial.sql +86 -0
- package/supabase/seed.sql +202 -0
- package/supabase/tests/add_step/basic_step_addition.test.sql +29 -0
- package/supabase/tests/add_step/circular_dependency.test.sql +21 -0
- package/supabase/tests/add_step/flow_isolation.test.sql +26 -0
- package/supabase/tests/add_step/idempotent_step_addition.test.sql +20 -0
- package/supabase/tests/add_step/invalid_step_slug.test.sql +16 -0
- package/supabase/tests/add_step/nonexistent_dependency.test.sql +16 -0
- package/supabase/tests/add_step/nonexistent_flow.test.sql +13 -0
- package/supabase/tests/add_step/options.test.sql +66 -0
- package/supabase/tests/add_step/step_with_dependency.test.sql +36 -0
- package/supabase/tests/add_step/step_with_multiple_dependencies.test.sql +46 -0
- package/supabase/tests/complete_task/archives_message.test.sql +67 -0
- package/supabase/tests/complete_task/completes_run_if_no_more_remaining_steps.test.sql +62 -0
- package/supabase/tests/complete_task/completes_task_and_updates_dependents.test.sql +64 -0
- package/supabase/tests/complete_task/decrements_remaining_steps_if_completing_step.test.sql +62 -0
- package/supabase/tests/complete_task/saves_output_when_completing_run.test.sql +57 -0
- package/supabase/tests/create_flow/flow_creation.test.sql +27 -0
- package/supabase/tests/create_flow/idempotency_and_duplicates.test.sql +26 -0
- package/supabase/tests/create_flow/invalid_slug.test.sql +13 -0
- package/supabase/tests/create_flow/options.test.sql +57 -0
- package/supabase/tests/fail_task/exponential_backoff.test.sql +70 -0
- package/supabase/tests/fail_task/mark_as_failed_if_no_retries_available.test.sql +49 -0
- package/supabase/tests/fail_task/respects_flow_retry_settings.test.sql +48 -0
- package/supabase/tests/fail_task/respects_step_retry_settings.test.sql +48 -0
- package/supabase/tests/fail_task/retry_task_if_retries_available.test.sql +39 -0
- package/supabase/tests/is_valid_slug.test.sql +72 -0
- package/supabase/tests/poll_for_tasks/builds_proper_input_from_deps_outputs.test.sql +35 -0
- package/supabase/tests/poll_for_tasks/hides_messages.test.sql +35 -0
- package/supabase/tests/poll_for_tasks/increments_attempts_count.test.sql +35 -0
- package/supabase/tests/poll_for_tasks/multiple_task_processing.test.sql +24 -0
- package/supabase/tests/poll_for_tasks/polls_only_queued_tasks.test.sql +35 -0
- package/supabase/tests/poll_for_tasks/reads_messages.test.sql +38 -0
- package/supabase/tests/poll_for_tasks/returns_no_tasks_if_no_step_task_for_message.test.sql +34 -0
- package/supabase/tests/poll_for_tasks/returns_no_tasks_if_queue_is_empty.test.sql +19 -0
- package/supabase/tests/poll_for_tasks/returns_no_tasks_when_qty_set_to_0.test.sql +22 -0
- package/supabase/tests/poll_for_tasks/sets_vt_delay_based_on_opt_timeout.test.sql +41 -0
- package/supabase/tests/poll_for_tasks/tasks_reapppear_if_not_processed_in_time.test.sql +59 -0
- package/supabase/tests/start_flow/creates_run.test.sql +24 -0
- package/supabase/tests/start_flow/creates_step_states_for_all_steps.test.sql +25 -0
- package/supabase/tests/start_flow/creates_step_tasks_only_for_root_steps.test.sql +54 -0
- package/supabase/tests/start_flow/returns_run.test.sql +24 -0
- package/supabase/tests/start_flow/sends_messages_on_the_queue.test.sql +50 -0
- package/supabase/tests/start_flow/starts_only_root_steps.test.sql +21 -0
- package/supabase/tests/step_dsl_is_idempotent.test.sql +34 -0
- package/tsconfig.json +16 -0
- package/tsconfig.lib.json +26 -0
- package/tsconfig.spec.json +35 -0
- package/vite.config.ts +57 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
begin;
|
|
2
|
+
|
|
3
|
+
select pgflow_tests.reset_db();
|
|
4
|
+
select pgflow_tests.setup_flow('sequential');
|
|
5
|
+
|
|
6
|
+
select pgflow.start_flow('sequential', '"hello"'::jsonb);
|
|
7
|
+
select * from pgflow.step_states;
|
|
8
|
+
select * from pgflow.step_tasks;
|
|
9
|
+
|
|
10
|
+
select * from pgflow.poll_for_tasks('sequential', 1, 1);
|
|
11
|
+
select * from pgflow.step_states;
|
|
12
|
+
select * from pgflow.step_tasks;
|
|
13
|
+
|
|
14
|
+
select pgflow.complete_task(
|
|
15
|
+
(select run_id from pgflow.runs limit 1),
|
|
16
|
+
'first',
|
|
17
|
+
0,
|
|
18
|
+
'"first completed"'::jsonb
|
|
19
|
+
);
|
|
20
|
+
select * from pgflow.step_states;
|
|
21
|
+
select * from pgflow.step_tasks;
|
|
22
|
+
|
|
23
|
+
select * from pgflow.poll_for_tasks('sequential', 1, 1);
|
|
24
|
+
|
|
25
|
+
select pgflow.complete_task(
|
|
26
|
+
(select run_id from pgflow.runs limit 1),
|
|
27
|
+
'second',
|
|
28
|
+
0,
|
|
29
|
+
'"second completed"'::jsonb
|
|
30
|
+
);
|
|
31
|
+
select * from pgflow.step_states;
|
|
32
|
+
select * from pgflow.step_tasks;
|
|
33
|
+
|
|
34
|
+
select * from pgflow.poll_for_tasks('sequential', 1, 1);
|
|
35
|
+
|
|
36
|
+
select pgflow.complete_task(
|
|
37
|
+
(select run_id from pgflow.runs limit 1),
|
|
38
|
+
'last',
|
|
39
|
+
0,
|
|
40
|
+
'"last completed"'::jsonb
|
|
41
|
+
);
|
|
42
|
+
select * from pgflow.step_states;
|
|
43
|
+
select * from pgflow.step_tasks;
|
|
44
|
+
|
|
45
|
+
select * from pgflow.runs;
|
|
46
|
+
|
|
47
|
+
rollback;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
\x
|
|
2
|
+
begin;
|
|
3
|
+
|
|
4
|
+
select pgflow_tests.reset_db();
|
|
5
|
+
select pgflow_tests.setup_flow('two_roots_left_right');
|
|
6
|
+
|
|
7
|
+
select pgflow.start_flow('two_roots_left_right', '"hello"'::jsonb);
|
|
8
|
+
select pgflow.poll_for_tasks('two_roots_left_right', 1, 1);
|
|
9
|
+
select pgflow.complete_task(
|
|
10
|
+
(select run_id from pgflow.runs limit 1),
|
|
11
|
+
'connected_root',
|
|
12
|
+
0,
|
|
13
|
+
'"connected_root completed"'::jsonb
|
|
14
|
+
);
|
|
15
|
+
select pgflow.poll_for_tasks('two_roots_left_right', 1, 1);
|
|
16
|
+
select pgflow.complete_task(
|
|
17
|
+
(select run_id from pgflow.runs limit 1),
|
|
18
|
+
'left',
|
|
19
|
+
0,
|
|
20
|
+
'"left completed"'::jsonb
|
|
21
|
+
);
|
|
22
|
+
select * from pgflow.step_tasks;
|
|
23
|
+
select pgflow.poll_for_tasks('two_roots_left_right', 1, 1);
|
|
24
|
+
select pgflow.complete_task(
|
|
25
|
+
(select run_id from pgflow.runs limit 1),
|
|
26
|
+
'disconnected_root',
|
|
27
|
+
0,
|
|
28
|
+
'"disconnected_root completed"'::jsonb
|
|
29
|
+
);
|
|
30
|
+
select pgflow.poll_for_tasks('two_roots_left_right', 1, 1);
|
|
31
|
+
-- select pgflow.complete_task(
|
|
32
|
+
-- (select run_id from pgflow.runs limit 1),
|
|
33
|
+
-- 'right',
|
|
34
|
+
-- 0,
|
|
35
|
+
-- '"right completed"'::jsonb
|
|
36
|
+
-- );
|
|
37
|
+
select pgflow.fail_task(
|
|
38
|
+
(select run_id from pgflow.runs limit 1),
|
|
39
|
+
'right',
|
|
40
|
+
0,
|
|
41
|
+
'invalid http request'
|
|
42
|
+
);
|
|
43
|
+
select pgflow.fail_task(
|
|
44
|
+
(select run_id from pgflow.runs limit 1),
|
|
45
|
+
'right',
|
|
46
|
+
0,
|
|
47
|
+
'invalid http request'
|
|
48
|
+
);
|
|
49
|
+
select pgflow.fail_task(
|
|
50
|
+
(select run_id from pgflow.runs limit 1),
|
|
51
|
+
'right',
|
|
52
|
+
0,
|
|
53
|
+
'invalid http request'
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
select * from pgflow.runs;
|
|
57
|
+
select * from pgflow.step_tasks;
|
|
58
|
+
select * from pgflow.step_states;
|
|
59
|
+
rollback;
|
package/schema.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg aria-roledescription="er" role="graphics-document document" viewBox="0 0 449.7414245605469 982" style="max-width: 449.741px; background-color: white;" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="100%" id="my-svg"><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#my-svg .error-icon{fill:#552222;}#my-svg .error-text{fill:#552222;stroke:#552222;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#333333;stroke:#333333;}#my-svg .marker.cross{stroke:#333333;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#my-svg p{margin:0;}#my-svg .entityBox{fill:#ECECFF;stroke:#9370DB;}#my-svg .attributeBoxOdd{fill:#ffffff;stroke:#9370DB;}#my-svg .attributeBoxEven{fill:#f2f2f2;stroke:#9370DB;}#my-svg .relationshipLabelBox{fill:hsl(80, 100%, 96.2745098039%);opacity:0.7;background-color:hsl(80, 100%, 96.2745098039%);}#my-svg .relationshipLabelBox rect{opacity:0.5;}#my-svg .relationshipLine{stroke:#333333;}#my-svg .entityTitleText{text-anchor:middle;font-size:18px;fill:#333;}#my-svg #MD_PARENT_START{fill:#f5f5f5!important;stroke:#333333!important;stroke-width:1;}#my-svg #MD_PARENT_END{fill:#f5f5f5!important;stroke:#333333!important;stroke-width:1;}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g/><defs><marker orient="auto" markerHeight="240" markerWidth="190" refY="7" refX="0" id="MD_PARENT_START"><path d="M 18,7 L9,13 L1,7 L9,1 Z"/></marker></defs><defs><marker orient="auto" markerHeight="28" markerWidth="20" refY="7" refX="19" id="MD_PARENT_END"><path d="M 18,7 L9,13 L1,7 L9,1 Z"/></marker></defs><defs><marker orient="auto" markerHeight="18" markerWidth="18" refY="9" refX="0" id="ONLY_ONE_START"><path d="M9,0 L9,18 M15,0 L15,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="18" markerWidth="18" refY="9" refX="18" id="ONLY_ONE_END"><path d="M3,0 L3,18 M9,0 L9,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="18" markerWidth="30" refY="9" refX="0" id="ZERO_OR_ONE_START"><circle r="6" cy="9" cx="21" fill="white" stroke="gray"/><path d="M9,0 L9,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="18" markerWidth="30" refY="9" refX="30" id="ZERO_OR_ONE_END"><circle r="6" cy="9" cx="9" fill="white" stroke="gray"/><path d="M21,0 L21,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="36" markerWidth="45" refY="18" refX="18" id="ONE_OR_MORE_START"><path d="M0,18 Q 18,0 36,18 Q 18,36 0,18 M42,9 L42,27" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="36" markerWidth="45" refY="18" refX="27" id="ONE_OR_MORE_END"><path d="M3,9 L3,27 M9,18 Q27,0 45,18 Q27,36 9,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="36" markerWidth="57" refY="18" refX="18" id="ZERO_OR_MORE_START"><circle r="6" cy="18" cx="48" fill="white" stroke="gray"/><path d="M0,18 Q18,0 36,18 Q18,36 0,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="36" markerWidth="57" refY="18" refX="39" id="ZERO_OR_MORE_END"><circle r="6" cy="18" cx="9" fill="white" stroke="gray"/><path d="M21,18 Q39,0 57,18 Q39,36 21,18" fill="none" stroke="gray"/></marker></defs><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M160.633,128L150.532,136.333C140.43,144.667,120.226,161.333,110.125,178C100.023,194.667,100.023,211.333,100.023,219.667L100.023,228" class="er relationshipLine"/><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M68.473,399L65.398,407.333C62.323,415.667,56.173,432.333,58.531,454.25C60.89,476.167,71.756,503.333,77.19,516.917L82.623,530.5" class="er relationshipLine"/><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M148.023,399L152.701,407.333C157.379,415.667,166.736,432.333,163.148,454.25C159.56,476.167,143.028,503.333,134.761,516.917L126.495,530.5" class="er relationshipLine"/><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M291.552,128L301.654,136.333C311.756,144.667,331.959,161.333,342.061,179.75C352.163,198.167,352.163,218.333,352.163,228.417L352.163,238.5" class="er relationshipLine"/><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M352.163,388.5L352.163,398.583C352.163,408.667,352.163,428.833,352.163,447.25C352.163,465.667,352.163,482.333,352.163,490.667L352.163,499" class="er relationshipLine"/><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M352.163,649L352.163,657.333C352.163,665.667,352.163,682.333,352.163,699C352.163,715.667,352.163,732.333,352.163,740.667L352.163,749" class="er relationshipLine"/><g transform="translate(153.99402618408203,20 )" id="entity-flows-f18f0530-88df-544b-a742-e42ede14479d"><rect height="108" width="144.19744873046875" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(72.09872436523438,12)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d" class="er entityLabel">flows</text><rect height="21" width="26.5899658203125" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-1-type" class="er entityLabel">text</text><rect height="21" width="93.8125" y="24" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,34.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-1-name" class="er entityLabel">flow_slug</text><rect height="21" width="23.79498291015625" y="24" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,34.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-1-key" class="er entityLabel">PK</text><rect height="21" width="26.5899658203125" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-2-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="45" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,55.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-2-name" class="er entityLabel">opt_max_attempts</text><rect height="21" width="23.79498291015625" y="45" x="120.4024658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,55.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-2-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-3-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="66" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,76.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-3-name" class="er entityLabel">opt_base_delay</text><rect height="21" width="23.79498291015625" y="66" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,76.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-3-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="87" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,97.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-4-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="87" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,97.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-4-name" class="er entityLabel">opt_timeout</text><rect height="21" width="23.79498291015625" y="87" x="120.4024658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,97.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-4-key" class="er entityLabel"/></g><g transform="translate(20,228 )" id="entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66"><rect height="171" width="160.0457763671875" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(80.02288818359375,12)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66" class="er entityLabel">steps</text><rect height="21" width="26.5899658203125" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-1-type" class="er entityLabel">text</text><rect height="21" width="93.8125" y="24" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,34.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-1-name" class="er entityLabel">flow_slug</text><rect height="21" width="39.643310546875" y="24" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,34.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-1-key" class="er entityLabel">PK,FK</text><rect height="21" width="26.5899658203125" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-2-type" class="er entityLabel">text</text><rect height="21" width="93.8125" y="45" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,55.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-2-name" class="er entityLabel">step_slug</text><rect height="21" width="39.643310546875" y="45" x="120.4024658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,55.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-2-key" class="er entityLabel">PK</text><rect height="21" width="26.5899658203125" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-3-type" class="er entityLabel">text</text><rect height="21" width="93.8125" y="66" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,76.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-3-name" class="er entityLabel">step_type</text><rect height="21" width="39.643310546875" y="66" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,76.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-3-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="87" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,97.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-4-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="87" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,97.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-4-name" class="er entityLabel">deps_count</text><rect height="21" width="39.643310546875" y="87" x="120.4024658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,97.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-4-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="108" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,118.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-5-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="108" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,118.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-5-name" class="er entityLabel">opt_max_attempts</text><rect height="21" width="39.643310546875" y="108" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,118.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-5-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="129" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,139.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-6-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="129" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,139.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-6-name" class="er entityLabel">opt_base_delay</text><rect height="21" width="39.643310546875" y="129" x="120.4024658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,139.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-6-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="150" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,160.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-7-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="150" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,160.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-7-name" class="er entityLabel">opt_timeout</text><rect height="21" width="39.643310546875" y="150" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,160.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-7-key" class="er entityLabel"/></g><g transform="translate(39.93402099609375,530.5 )" id="entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e"><rect height="87" width="120.177734375" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(60.0888671875,12)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e" class="er entityLabel">deps</text><rect height="21" width="26.5899658203125" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-1-type" class="er entityLabel">text</text><rect height="21" width="53.9444580078125" y="24" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,34.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-1-name" class="er entityLabel">flow_slug</text><rect height="21" width="39.643310546875" y="24" x="80.534423828125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(85.534423828125,34.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-1-key" class="er entityLabel">PK,FK</text><rect height="21" width="26.5899658203125" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-2-type" class="er entityLabel">text</text><rect height="21" width="53.9444580078125" y="45" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,55.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-2-name" class="er entityLabel">dep_slug</text><rect height="21" width="39.643310546875" y="45" x="80.534423828125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(85.534423828125,55.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-2-key" class="er entityLabel">PK,FK</text><rect height="21" width="26.5899658203125" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-3-type" class="er entityLabel">text</text><rect height="21" width="53.9444580078125" y="66" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,76.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-3-name" class="er entityLabel">step_slug</text><rect height="21" width="39.643310546875" y="66" x="80.534423828125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(85.534423828125,76.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-3-key" class="er entityLabel">PK,FK</text></g><g transform="translate(280.0457763671875,238.5 )" id="entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf"><rect height="150" width="144.23367309570312" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(72.11683654785156,12)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf" class="er entityLabel">runs</text><rect height="21" width="35.688690185546875" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-1-type" class="er entityLabel">uuid</text><rect height="21" width="84.75" y="24" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,34.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-1-name" class="er entityLabel">run_id</text><rect height="21" width="23.79498291015625" y="24" x="120.43869018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,34.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-1-key" class="er entityLabel">PK</text><rect height="21" width="35.688690185546875" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-2-type" class="er entityLabel">text</text><rect height="21" width="84.75" y="45" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,55.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-2-name" class="er entityLabel">flow_slug</text><rect height="21" width="23.79498291015625" y="45" x="120.43869018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,55.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-2-key" class="er entityLabel">FK</text><rect height="21" width="35.688690185546875" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-3-type" class="er entityLabel">text</text><rect height="21" width="84.75" y="66" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,76.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-3-name" class="er entityLabel">status</text><rect height="21" width="23.79498291015625" y="66" x="120.43869018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,76.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-3-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="87" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,97.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-4-type" class="er entityLabel">jsonb</text><rect height="21" width="84.75" y="87" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,97.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-4-name" class="er entityLabel">input</text><rect height="21" width="23.79498291015625" y="87" x="120.43869018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,97.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-4-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="108" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,118.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-5-type" class="er entityLabel">jsonb</text><rect height="21" width="84.75" y="108" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,118.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-5-name" class="er entityLabel">output</text><rect height="21" width="23.79498291015625" y="108" x="120.43869018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,118.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-5-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="129" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,139.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-6-type" class="er entityLabel">int</text><rect height="21" width="84.75" y="129" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,139.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-6-name" class="er entityLabel">remaining_steps</text><rect height="21" width="23.79498291015625" y="129" x="120.43869018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,139.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-6-key" class="er entityLabel"/></g><g transform="translate(275.4497375488281,499 )" id="entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4"><rect height="150" width="153.42575073242188" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(76.71287536621094,12)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4" class="er entityLabel">step_states</text><rect height="21" width="29.594940185546875" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-1-type" class="er entityLabel">text</text><rect height="21" width="84.1875" y="24" x="29.594940185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,34.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-1-name" class="er entityLabel">flow_slug</text><rect height="21" width="39.643310546875" y="24" x="113.78244018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,34.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-1-key" class="er entityLabel">FK</text><rect height="21" width="29.594940185546875" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-2-type" class="er entityLabel">uuid</text><rect height="21" width="84.1875" y="45" x="29.594940185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,55.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-2-name" class="er entityLabel">run_id</text><rect height="21" width="39.643310546875" y="45" x="113.78244018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,55.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-2-key" class="er entityLabel">PK,FK</text><rect height="21" width="29.594940185546875" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-3-type" class="er entityLabel">text</text><rect height="21" width="84.1875" y="66" x="29.594940185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,76.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-3-name" class="er entityLabel">step_slug</text><rect height="21" width="39.643310546875" y="66" x="113.78244018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,76.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-3-key" class="er entityLabel">PK,FK</text><rect height="21" width="29.594940185546875" y="87" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,97.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-4-type" class="er entityLabel">text</text><rect height="21" width="84.1875" y="87" x="29.594940185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,97.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-4-name" class="er entityLabel">status</text><rect height="21" width="39.643310546875" y="87" x="113.78244018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,97.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-4-key" class="er entityLabel"/><rect height="21" width="29.594940185546875" y="108" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,118.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-5-type" class="er entityLabel">int</text><rect height="21" width="84.1875" y="108" x="29.594940185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,118.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-5-name" class="er entityLabel">remaining_tasks</text><rect height="21" width="39.643310546875" y="108" x="113.78244018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,118.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-5-key" class="er entityLabel"/><rect height="21" width="29.594940185546875" y="129" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,139.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-6-type" class="er entityLabel">int</text><rect height="21" width="84.1875" y="129" x="29.594940185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,139.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-6-name" class="er entityLabel">remaining_deps</text><rect height="21" width="39.643310546875" y="129" x="113.78244018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,139.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-6-key" class="er entityLabel"/></g><g transform="translate(274.58380126953125,749 )" id="entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8"><rect height="213" width="155.15762329101562" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(77.57881164550781,12)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8" class="er entityLabel">step_tasks</text><rect height="21" width="35.688690185546875" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-1-type" class="er entityLabel">text</text><rect height="21" width="79.82562255859375" y="24" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,34.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-1-name" class="er entityLabel">flow_slug</text><rect height="21" width="39.643310546875" y="24" x="115.51431274414062" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,34.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-1-key" class="er entityLabel">FK</text><rect height="21" width="35.688690185546875" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-2-type" class="er entityLabel">uuid</text><rect height="21" width="79.82562255859375" y="45" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,55.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-2-name" class="er entityLabel">run_id</text><rect height="21" width="39.643310546875" y="45" x="115.51431274414062" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,55.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-2-key" class="er entityLabel">PK,FK</text><rect height="21" width="35.688690185546875" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-3-type" class="er entityLabel">text</text><rect height="21" width="79.82562255859375" y="66" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,76.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-3-name" class="er entityLabel">step_slug</text><rect height="21" width="39.643310546875" y="66" x="115.51431274414062" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,76.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-3-key" class="er entityLabel">PK,FK</text><rect height="21" width="35.688690185546875" y="87" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,97.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-4-type" class="er entityLabel">bigint</text><rect height="21" width="79.82562255859375" y="87" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,97.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-4-name" class="er entityLabel">message_id</text><rect height="21" width="39.643310546875" y="87" x="115.51431274414062" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,97.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-4-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="108" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,118.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-5-type" class="er entityLabel">int</text><rect height="21" width="79.82562255859375" y="108" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,118.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-5-name" class="er entityLabel">task_index</text><rect height="21" width="39.643310546875" y="108" x="115.51431274414062" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,118.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-5-key" class="er entityLabel">PK</text><rect height="21" width="35.688690185546875" y="129" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,139.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-6-type" class="er entityLabel">text</text><rect height="21" width="79.82562255859375" y="129" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,139.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-6-name" class="er entityLabel">status</text><rect height="21" width="39.643310546875" y="129" x="115.51431274414062" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,139.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-6-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="150" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,160.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-7-type" class="er entityLabel">int</text><rect height="21" width="79.82562255859375" y="150" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,160.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-7-name" class="er entityLabel">attempts_count</text><rect height="21" width="39.643310546875" y="150" x="115.51431274414062" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,160.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-7-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="171" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,181.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-8-type" class="er entityLabel">text</text><rect height="21" width="79.82562255859375" y="171" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,181.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-8-name" class="er entityLabel">error_message</text><rect height="21" width="39.643310546875" y="171" x="115.51431274414062" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,181.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-8-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="192" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,202.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-9-type" class="er entityLabel">jsonb</text><rect height="21" width="79.82562255859375" y="192" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,202.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-9-name" class="er entityLabel">output</text><rect height="21" width="39.643310546875" y="192" x="115.51431274414062" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,202.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-9-key" class="er entityLabel"/></g><rect height="14" width="19.359375" y="162.96568298339844" x="106.04055786132812" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="169.96568298339844" x="115.72024536132812" id="rel1" class="er relationshipLabel">has</text><rect height="14" width="80.734375" y="458.8131103515625" x="20.040935516357422" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="465.8131103515625" x="60.40812301635742" id="rel2" class="er relationshipLabel">is_dependency</text><rect height="14" width="66.078125" y="460.0412902832031" x="126.8541259765625" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="467.0412902832031" x="159.8931884765625" id="rel3" class="er relationshipLabel">depends_on</text><rect height="14" width="60.703125" y="167.44549560546875" x="308.50225830078125" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="174.44549560546875" x="338.85382080078125" id="rel4" class="er relationshipLabel">instantiates</text><rect height="14" width="44.703125" y="436.75" x="329.8114318847656" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="443.75" x="352.1629943847656" id="rel5" class="er relationshipLabel">contains</text><rect height="14" width="19.359375" y="692" x="342.4833068847656" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="699" x="352.1629943847656" id="rel6" class="er relationshipLabel">has</text></svg>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
BEGIN {
|
|
2
|
+
# ANSI color codes
|
|
3
|
+
RED="\033[31m";
|
|
4
|
+
GREEN="\033[32m";
|
|
5
|
+
YELLOW="\033[33m";
|
|
6
|
+
GRAY="\033[90m";
|
|
7
|
+
BOLD="\033[1m";
|
|
8
|
+
RESET="\033[0m";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/Dubious|Failed|error|exit 1|Result: FAIL/ {
|
|
12
|
+
print RED $0 RESET;
|
|
13
|
+
next;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# Match any line containing ERROR: (PostgreSQL error messages)
|
|
17
|
+
/ERROR:/ {
|
|
18
|
+
print RED $0 RESET;
|
|
19
|
+
next;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Match DETAIL: and CONTEXT: lines that are part of PostgreSQL error messages
|
|
23
|
+
/DETAIL:|CONTEXT:/ {
|
|
24
|
+
print RED $0 RESET;
|
|
25
|
+
next;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/ok$/ {
|
|
29
|
+
print GREEN $0 RESET;
|
|
30
|
+
next;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/\.\.\.+/ {
|
|
34
|
+
test = $1;
|
|
35
|
+
result = $NF;
|
|
36
|
+
if (result == "ok") {
|
|
37
|
+
printf "%s %s %s\n", test, GRAY RESET, GREEN result RESET;
|
|
38
|
+
} else {
|
|
39
|
+
printf "%s %s %s\n", RED test RESET, GRAY RESET, RED result RESET;
|
|
40
|
+
}
|
|
41
|
+
next;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/Test Summary Report|-------------------/ {
|
|
45
|
+
print YELLOW BOLD $0 RESET;
|
|
46
|
+
next;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/\(Wstat:.*/ {
|
|
50
|
+
sub(/^[[:space:]]+/, "");
|
|
51
|
+
filename = $1;
|
|
52
|
+
print YELLOW " " RED filename RESET YELLOW $2 $3 $4 $5 $6 RESET;
|
|
53
|
+
next;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/^Files=|^Result:/ {
|
|
57
|
+
if ($0 ~ /FAIL/) {
|
|
58
|
+
print RED BOLD $0 RESET;
|
|
59
|
+
} else {
|
|
60
|
+
print YELLOW $0 RESET;
|
|
61
|
+
}
|
|
62
|
+
next;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/Try rerunning/ {
|
|
66
|
+
print YELLOW $0 RESET;
|
|
67
|
+
next;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
{
|
|
71
|
+
print;
|
|
72
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type postgres from 'postgres';
|
|
2
|
+
import type {
|
|
3
|
+
StepTaskRecord,
|
|
4
|
+
IPgflowClient,
|
|
5
|
+
StepTaskKey,
|
|
6
|
+
RunRow,
|
|
7
|
+
} from './types.ts';
|
|
8
|
+
import type { Json } from './types.ts';
|
|
9
|
+
import type { AnyFlow, ExtractFlowInput } from '@pgflow/dsl';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Implementation of IPgflowClient that uses direct SQL calls to pgflow functions
|
|
13
|
+
*/
|
|
14
|
+
export class PgflowSqlClient<TFlow extends AnyFlow>
|
|
15
|
+
implements IPgflowClient<TFlow>
|
|
16
|
+
{
|
|
17
|
+
constructor(private readonly sql: postgres.Sql) {}
|
|
18
|
+
|
|
19
|
+
async pollForTasks(
|
|
20
|
+
queueName: string,
|
|
21
|
+
batchSize = 20,
|
|
22
|
+
visibilityTimeout = 2,
|
|
23
|
+
maxPollSeconds = 5,
|
|
24
|
+
pollIntervalMs = 200
|
|
25
|
+
): Promise<StepTaskRecord<TFlow>[]> {
|
|
26
|
+
return await this.sql<StepTaskRecord<TFlow>[]>`
|
|
27
|
+
SELECT *
|
|
28
|
+
FROM pgflow.poll_for_tasks(
|
|
29
|
+
queue_name => ${queueName},
|
|
30
|
+
vt => ${visibilityTimeout},
|
|
31
|
+
qty => ${batchSize},
|
|
32
|
+
max_poll_seconds => ${maxPollSeconds},
|
|
33
|
+
poll_interval_ms => ${pollIntervalMs}
|
|
34
|
+
);
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async completeTask(stepTask: StepTaskKey, output?: Json): Promise<void> {
|
|
39
|
+
await this.sql`
|
|
40
|
+
SELECT pgflow.complete_task(
|
|
41
|
+
run_id => ${stepTask.run_id}::uuid,
|
|
42
|
+
step_slug => ${stepTask.step_slug}::text,
|
|
43
|
+
task_index => ${0}::int,
|
|
44
|
+
output => ${this.sql.json(output || null)}::jsonb
|
|
45
|
+
);
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async failTask(stepTask: StepTaskKey, error: unknown): Promise<void> {
|
|
50
|
+
const errorString =
|
|
51
|
+
typeof error === 'string'
|
|
52
|
+
? error
|
|
53
|
+
: error instanceof Error
|
|
54
|
+
? error.message
|
|
55
|
+
: JSON.stringify(error);
|
|
56
|
+
|
|
57
|
+
await this.sql`
|
|
58
|
+
SELECT pgflow.fail_task(
|
|
59
|
+
run_id => ${stepTask.run_id}::uuid,
|
|
60
|
+
step_slug => ${stepTask.step_slug}::text,
|
|
61
|
+
task_index => ${0}::int,
|
|
62
|
+
error_message => ${errorString}::text
|
|
63
|
+
);
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async startFlow<TFlow extends AnyFlow>(
|
|
68
|
+
flow: TFlow,
|
|
69
|
+
input: ExtractFlowInput<TFlow>
|
|
70
|
+
): Promise<RunRow> {
|
|
71
|
+
const results = await this.sql<RunRow[]>`
|
|
72
|
+
SELECT * FROM pgflow.start_flow(${flow.slug}::text, ${this.sql.json(
|
|
73
|
+
input
|
|
74
|
+
)}::jsonb);
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
if (results.length === 0) {
|
|
78
|
+
throw new Error(`Failed to start flow ${flow.slug}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const [flowRun] = results;
|
|
82
|
+
|
|
83
|
+
return flowRun;
|
|
84
|
+
}
|
|
85
|
+
}
|