mirror of
https://github.com/hatchet-dev/hatchet.git
synced 2026-02-28 04:48:54 -06:00
1075 lines
29 KiB
SQL
1075 lines
29 KiB
SQL
-- name: ListActiveConcurrencyStrategies :many
|
|
WITH earliest_workflow_versions AS (
|
|
-- We select the earliest workflow versions with an active concurrency queue. The reason
|
|
-- is that we'd like to drain previous concurrency queues gracefully, otherwise we risk
|
|
-- running more tasks than we should.
|
|
SELECT DISTINCT ON("workflowId")
|
|
"workflowId",
|
|
wv."id" AS "workflowVersionId"
|
|
FROM
|
|
v1_step_concurrency sc
|
|
JOIN
|
|
"WorkflowVersion" wv ON wv."id" = sc.workflow_version_id
|
|
WHERE
|
|
sc.tenant_id = @tenantId::uuid AND
|
|
sc.is_active = TRUE
|
|
ORDER BY
|
|
"workflowId", wv."order" ASC
|
|
)
|
|
SELECT
|
|
sc.*
|
|
FROM
|
|
v1_step_concurrency sc
|
|
JOIN
|
|
"WorkflowVersion" wv ON wv."id" = sc.workflow_version_id
|
|
JOIN
|
|
earliest_workflow_versions ewv ON ewv."workflowVersionId" = wv."id"
|
|
WHERE
|
|
sc.tenant_id = @tenantId::uuid AND
|
|
sc.is_active = TRUE;
|
|
|
|
-- name: ListConcurrencyStrategiesByStepId :many
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_step_concurrency
|
|
WHERE
|
|
tenant_id = @tenantId::uuid AND
|
|
step_id = ANY(@stepIds::uuid[])
|
|
ORDER BY
|
|
id ASC;
|
|
|
|
-- name: CheckStrategyActive :one
|
|
-- A strategy is active if the workflow is not deleted, and it is attached to the latest workflow version or it has
|
|
-- at least one concurrency slot that is not filled (the concurrency slot could be on the parent).
|
|
WITH latest_workflow_version AS (
|
|
SELECT DISTINCT ON("workflowId")
|
|
"workflowId",
|
|
wv."id" AS "workflowVersionId"
|
|
FROM
|
|
"WorkflowVersion" wv
|
|
WHERE
|
|
wv."workflowId" = @workflowId::uuid
|
|
AND wv."deletedAt" IS NULL
|
|
ORDER BY "workflowId", "order" DESC
|
|
LIMIT 1
|
|
), first_active_strategy AS (
|
|
-- Get the first active strategy for the workflow version
|
|
SELECT
|
|
sc.id
|
|
FROM
|
|
v1_step_concurrency sc
|
|
WHERE
|
|
sc.tenant_id = @tenantId::uuid AND
|
|
sc.workflow_id = @workflowId::uuid AND
|
|
sc.workflow_version_id = @workflowVersionId::uuid AND
|
|
sc.is_active = TRUE
|
|
ORDER BY
|
|
sc.id ASC
|
|
LIMIT 1
|
|
), active_slot AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid AND
|
|
strategy_id = @strategyId::bigint
|
|
-- Note we don't check for is_filled=False, because is_filled=True could imply that the task
|
|
-- gets retried and the slot is still active.
|
|
LIMIT 1
|
|
), active_parent_slot AS (
|
|
SELECT
|
|
wcs.*
|
|
FROM
|
|
v1_concurrency_slot cs
|
|
JOIN
|
|
v1_workflow_concurrency_slot wcs ON (wcs.strategy_id, wcs.workflow_version_id, wcs.workflow_run_id) = (cs.parent_strategy_id, cs.workflow_version_id, cs.workflow_run_id)
|
|
WHERE
|
|
cs.tenant_id = @tenantId::uuid AND
|
|
cs.strategy_id = @strategyId::bigint
|
|
-- Note we don't check for is_filled=False, because is_filled=True could imply that the task
|
|
-- gets retried and the slot is still active.
|
|
LIMIT 1
|
|
), is_active AS (
|
|
SELECT
|
|
EXISTS(SELECT 1 FROM latest_workflow_version) AND
|
|
(
|
|
-- We must match the first active strategy, otherwise we could have another concurrency strategy
|
|
-- that is active and has this concurrency strategy as a child.
|
|
(first_active_strategy.id != @strategyId::bigint) OR
|
|
latest_workflow_version."workflowVersionId" = @workflowVersionId::uuid OR
|
|
EXISTS(SELECT 1 FROM active_slot) OR
|
|
EXISTS(SELECT 1 FROM active_parent_slot)
|
|
) AS "isActive"
|
|
FROM
|
|
latest_workflow_version, first_active_strategy
|
|
)
|
|
SELECT COALESCE((SELECT "isActive" FROM is_active), FALSE)::bool AS "isActive";
|
|
|
|
-- name: SetConcurrencyStrategyInactive :exec
|
|
UPDATE
|
|
v1_step_concurrency
|
|
SET
|
|
is_active = FALSE
|
|
WHERE
|
|
workflow_id = @workflowId::uuid AND
|
|
workflow_version_id = @workflowVersionId::uuid AND
|
|
step_id = @stepId::uuid AND
|
|
id = @strategyId::bigint;
|
|
|
|
-- name: ConcurrencyAdvisoryLock :exec
|
|
SELECT pg_advisory_xact_lock(@key::bigint);
|
|
|
|
-- name: TryConcurrencyAdvisoryLock :one
|
|
SELECT pg_try_advisory_xact_lock(@key::bigint) AS "locked";
|
|
|
|
-- name: RunParentGroupRoundRobin :exec
|
|
WITH eligible_slots_per_group AS (
|
|
SELECT wsc.*
|
|
FROM (
|
|
SELECT DISTINCT key
|
|
FROM v1_workflow_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid
|
|
AND strategy_id = @strategyId::bigint
|
|
) distinct_keys
|
|
JOIN LATERAL (
|
|
SELECT *
|
|
FROM v1_workflow_concurrency_slot wcs_all
|
|
WHERE
|
|
wcs_all.key = distinct_keys.key
|
|
AND wcs_all.tenant_id = @tenantId::uuid
|
|
AND wcs_all.strategy_id = @strategyId::bigint
|
|
ORDER BY wcs_all.priority DESC, wcs_all.sort_id ASC
|
|
LIMIT @maxRuns::int
|
|
) wsc ON true
|
|
), eligible_slots AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_workflow_concurrency_slot
|
|
WHERE
|
|
(strategy_id, workflow_version_id, workflow_run_id) IN (
|
|
SELECT
|
|
es.strategy_id,
|
|
es.workflow_version_id,
|
|
es.workflow_run_id
|
|
FROM
|
|
eligible_slots_per_group es
|
|
)
|
|
AND is_filled = FALSE
|
|
ORDER BY
|
|
strategy_id, workflow_version_id, workflow_run_id
|
|
FOR UPDATE
|
|
)
|
|
UPDATE
|
|
v1_workflow_concurrency_slot
|
|
SET
|
|
is_filled = TRUE
|
|
FROM
|
|
eligible_slots
|
|
WHERE
|
|
v1_workflow_concurrency_slot.strategy_id = eligible_slots.strategy_id AND
|
|
v1_workflow_concurrency_slot.workflow_version_id = eligible_slots.workflow_version_id AND
|
|
v1_workflow_concurrency_slot.workflow_run_id = eligible_slots.workflow_run_id;
|
|
|
|
-- name: RunGroupRoundRobin :many
|
|
-- Used for round-robin scheduling when a strategy doesn't have a parent strategy
|
|
WITH eligible_slots_per_group AS (
|
|
SELECT cs.*
|
|
FROM (
|
|
SELECT DISTINCT key
|
|
FROM v1_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid
|
|
AND strategy_id = @strategyId::bigint
|
|
) distinct_keys
|
|
JOIN LATERAL (
|
|
SELECT *
|
|
FROM v1_concurrency_slot wcs_all
|
|
WHERE
|
|
wcs_all.key = distinct_keys.key
|
|
AND wcs_all.tenant_id = @tenantId::uuid
|
|
AND wcs_all.strategy_id = @strategyId::bigint
|
|
ORDER BY wcs_all.sort_id ASC
|
|
LIMIT @maxRuns::int
|
|
) wsc ON true
|
|
), schedule_timeout_slots AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid AND
|
|
strategy_id = @strategyId::bigint AND
|
|
schedule_timeout_at < NOW() AND
|
|
is_filled = FALSE
|
|
ORDER BY
|
|
task_id, task_inserted_at
|
|
FOR UPDATE
|
|
), eligible_slots AS (
|
|
SELECT
|
|
cs.*
|
|
FROM
|
|
v1_concurrency_slot cs
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count, tenant_id, strategy_id) IN (
|
|
SELECT
|
|
es.task_inserted_at,
|
|
es.task_id,
|
|
es.task_retry_count,
|
|
es.tenant_id,
|
|
es.strategy_id
|
|
FROM
|
|
eligible_slots_per_group es
|
|
)
|
|
AND is_filled = FALSE
|
|
ORDER BY
|
|
task_id, task_inserted_at
|
|
FOR UPDATE
|
|
), updated_slots AS (
|
|
UPDATE
|
|
v1_concurrency_slot
|
|
SET
|
|
is_filled = TRUE
|
|
FROM
|
|
eligible_slots
|
|
WHERE
|
|
v1_concurrency_slot.task_id = eligible_slots.task_id AND
|
|
v1_concurrency_slot.task_inserted_at = eligible_slots.task_inserted_at AND
|
|
v1_concurrency_slot.task_retry_count = eligible_slots.task_retry_count AND
|
|
v1_concurrency_slot.tenant_id = eligible_slots.tenant_id AND
|
|
v1_concurrency_slot.strategy_id = eligible_slots.strategy_id AND
|
|
v1_concurrency_slot.key = eligible_slots.key
|
|
RETURNING
|
|
v1_concurrency_slot.*
|
|
), deleted_slots AS (
|
|
DELETE FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count) IN (
|
|
SELECT
|
|
c.task_inserted_at,
|
|
c.task_id,
|
|
c.task_retry_count
|
|
FROM
|
|
schedule_timeout_slots c
|
|
)
|
|
)
|
|
SELECT
|
|
*,
|
|
'SCHEDULING_TIMED_OUT' AS "operation"
|
|
FROM
|
|
schedule_timeout_slots
|
|
UNION ALL
|
|
SELECT
|
|
*,
|
|
'RUNNING' AS "operation"
|
|
FROM
|
|
updated_slots;
|
|
|
|
-- name: RunChildGroupRoundRobin :many
|
|
-- Used for round-robin scheduling when a strategy has a parent strategy. It inherits the concurrency
|
|
-- settings of the parent, so we just set the is_filled flag to true if the parent slot is filled.
|
|
WITH filled_parent_slots AS (
|
|
SELECT *
|
|
FROM v1_workflow_concurrency_slot wcs
|
|
WHERE
|
|
wcs.tenant_id = @tenantId::uuid
|
|
AND wcs.strategy_id = @parentStrategyId::bigint
|
|
AND wcs.is_filled = TRUE
|
|
), eligible_slots_per_group AS (
|
|
SELECT cs_all.*
|
|
FROM v1_concurrency_slot cs_all
|
|
JOIN
|
|
filled_parent_slots wcs ON (wcs.strategy_id, wcs.workflow_version_id, wcs.workflow_run_id) = (cs_all.parent_strategy_id, cs_all.workflow_version_id, cs_all.workflow_run_id)
|
|
WHERE
|
|
cs_all.tenant_id = @tenantId::uuid
|
|
AND cs_all.strategy_id = @strategyId::bigint
|
|
AND (
|
|
cs_all.schedule_timeout_at >= NOW() OR
|
|
cs_all.is_filled = TRUE
|
|
)
|
|
), schedule_timeout_slots AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid AND
|
|
strategy_id = @strategyId::bigint AND
|
|
schedule_timeout_at < NOW() AND
|
|
is_filled = FALSE
|
|
ORDER BY
|
|
task_id, task_inserted_at
|
|
FOR UPDATE
|
|
), eligible_slots AS (
|
|
SELECT
|
|
cs.*
|
|
FROM
|
|
v1_concurrency_slot cs
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count, tenant_id, strategy_id) IN (
|
|
SELECT
|
|
es.task_inserted_at,
|
|
es.task_id,
|
|
es.task_retry_count,
|
|
es.tenant_id,
|
|
es.strategy_id
|
|
FROM
|
|
eligible_slots_per_group es
|
|
)
|
|
AND is_filled = FALSE
|
|
ORDER BY
|
|
task_id, task_inserted_at
|
|
FOR UPDATE
|
|
), updated_slots AS (
|
|
UPDATE
|
|
v1_concurrency_slot
|
|
SET
|
|
is_filled = TRUE
|
|
FROM
|
|
eligible_slots
|
|
WHERE
|
|
v1_concurrency_slot.task_id = eligible_slots.task_id AND
|
|
v1_concurrency_slot.task_inserted_at = eligible_slots.task_inserted_at AND
|
|
v1_concurrency_slot.task_retry_count = eligible_slots.task_retry_count AND
|
|
v1_concurrency_slot.tenant_id = eligible_slots.tenant_id AND
|
|
v1_concurrency_slot.strategy_id = eligible_slots.strategy_id AND
|
|
v1_concurrency_slot.key = eligible_slots.key
|
|
RETURNING
|
|
v1_concurrency_slot.*
|
|
), deleted_slots AS (
|
|
DELETE FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count) IN (
|
|
SELECT
|
|
c.task_inserted_at,
|
|
c.task_id,
|
|
c.task_retry_count
|
|
FROM
|
|
schedule_timeout_slots c
|
|
)
|
|
)
|
|
SELECT
|
|
*,
|
|
'SCHEDULING_TIMED_OUT' AS "operation"
|
|
FROM
|
|
schedule_timeout_slots
|
|
UNION ALL
|
|
SELECT
|
|
*,
|
|
'RUNNING' AS "operation"
|
|
FROM
|
|
updated_slots;
|
|
|
|
-- name: RunParentCancelInProgress :exec
|
|
WITH eligible_running_slots AS (
|
|
SELECT wsc.*
|
|
FROM (
|
|
SELECT DISTINCT key
|
|
FROM tmp_workflow_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid
|
|
AND strategy_id = @strategyId::bigint
|
|
) distinct_keys
|
|
JOIN LATERAL (
|
|
SELECT *
|
|
FROM tmp_workflow_concurrency_slot wcs_all
|
|
WHERE
|
|
wcs_all.key = distinct_keys.key
|
|
AND wcs_all.tenant_id = @tenantId::uuid
|
|
AND wcs_all.strategy_id = @strategyId::bigint
|
|
ORDER BY wcs_all.sort_id DESC
|
|
LIMIT @maxRuns::int
|
|
) wsc ON true
|
|
), slots_to_run AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_workflow_concurrency_slot
|
|
WHERE
|
|
(strategy_id, workflow_version_id, workflow_run_id) IN (
|
|
SELECT
|
|
ers.strategy_id,
|
|
ers.workflow_version_id,
|
|
ers.workflow_run_id
|
|
FROM
|
|
eligible_running_slots ers
|
|
)
|
|
ORDER BY
|
|
strategy_id, workflow_version_id, workflow_run_id
|
|
FOR UPDATE
|
|
), update_tmp_table AS (
|
|
UPDATE
|
|
tmp_workflow_concurrency_slot wsc
|
|
SET
|
|
is_filled = TRUE
|
|
FROM
|
|
slots_to_run
|
|
WHERE
|
|
wsc.strategy_id = slots_to_run.strategy_id AND
|
|
wsc.workflow_version_id = slots_to_run.workflow_version_id AND
|
|
wsc.workflow_run_id = slots_to_run.workflow_run_id
|
|
)
|
|
UPDATE
|
|
v1_workflow_concurrency_slot wsc
|
|
SET
|
|
is_filled = TRUE
|
|
FROM
|
|
slots_to_run sr
|
|
WHERE
|
|
wsc.strategy_id = sr.strategy_id AND
|
|
wsc.workflow_version_id = sr.workflow_version_id AND
|
|
wsc.workflow_run_id = sr.workflow_run_id;
|
|
|
|
-- name: RunChildCancelInProgress :many
|
|
WITH slots AS (
|
|
SELECT
|
|
task_id,
|
|
task_inserted_at,
|
|
task_retry_count,
|
|
cs.tenant_id,
|
|
cs.strategy_id,
|
|
cs.key,
|
|
cs.is_filled,
|
|
-- Order slots by rn desc, seqnum desc to ensure that the most recent tasks will be run
|
|
row_number() OVER (PARTITION BY cs.key ORDER BY cs.sort_id DESC) AS rn,
|
|
row_number() OVER (ORDER BY cs.sort_id DESC) AS seqnum
|
|
FROM
|
|
v1_concurrency_slot cs
|
|
JOIN
|
|
tmp_workflow_concurrency_slot wcs ON (wcs.strategy_id, wcs.workflow_version_id, wcs.workflow_run_id) = (cs.parent_strategy_id, cs.workflow_version_id, cs.workflow_run_id)
|
|
WHERE
|
|
cs.tenant_id = @tenantId::uuid AND
|
|
cs.strategy_id = @strategyId::bigint AND
|
|
(
|
|
cs.parent_strategy_id IS NULL OR
|
|
wcs.is_filled = TRUE
|
|
) AND
|
|
(
|
|
schedule_timeout_at >= NOW() OR
|
|
cs.is_filled = TRUE
|
|
)
|
|
), schedule_timeout_slots AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid AND
|
|
strategy_id = @strategyId::bigint AND
|
|
schedule_timeout_at < NOW() AND
|
|
is_filled = FALSE
|
|
), eligible_running_slots AS (
|
|
SELECT
|
|
task_id,
|
|
task_inserted_at,
|
|
task_retry_count,
|
|
tenant_id,
|
|
strategy_id,
|
|
key,
|
|
is_filled,
|
|
rn,
|
|
seqnum
|
|
FROM
|
|
slots
|
|
WHERE
|
|
rn <= @maxRuns::int
|
|
), slots_to_cancel AS (
|
|
SELECT
|
|
cs.*
|
|
FROM
|
|
v1_concurrency_slot cs
|
|
JOIN
|
|
tmp_workflow_concurrency_slot wcs ON (wcs.strategy_id, wcs.workflow_version_id, wcs.workflow_run_id) = (cs.parent_strategy_id, cs.workflow_version_id, cs.workflow_run_id)
|
|
WHERE
|
|
cs.tenant_id = @tenantId::uuid AND
|
|
cs.strategy_id = @strategyId::bigint AND
|
|
(cs.task_inserted_at, cs.task_id, cs.task_retry_count) NOT IN (
|
|
SELECT
|
|
ers.task_inserted_at,
|
|
ers.task_id,
|
|
ers.task_retry_count
|
|
FROM
|
|
eligible_running_slots ers
|
|
)
|
|
ORDER BY
|
|
cs.task_id, cs.task_inserted_at
|
|
FOR UPDATE
|
|
), slots_to_run AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count, tenant_id, strategy_id) IN (
|
|
SELECT
|
|
ers.task_inserted_at,
|
|
ers.task_id,
|
|
ers.task_retry_count,
|
|
ers.tenant_id,
|
|
ers.strategy_id
|
|
FROM
|
|
eligible_running_slots ers
|
|
ORDER BY
|
|
rn, seqnum
|
|
)
|
|
ORDER BY
|
|
task_id, task_inserted_at
|
|
FOR UPDATE
|
|
), updated_slots AS (
|
|
UPDATE
|
|
v1_concurrency_slot
|
|
SET
|
|
is_filled = TRUE
|
|
FROM
|
|
slots_to_run
|
|
WHERE
|
|
v1_concurrency_slot.task_id = slots_to_run.task_id AND
|
|
v1_concurrency_slot.task_inserted_at = slots_to_run.task_inserted_at AND
|
|
v1_concurrency_slot.task_retry_count = slots_to_run.task_retry_count AND
|
|
v1_concurrency_slot.key = slots_to_run.key AND
|
|
v1_concurrency_slot.is_filled = FALSE
|
|
RETURNING
|
|
v1_concurrency_slot.*
|
|
), deleted_slots AS (
|
|
DELETE FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count) IN (
|
|
SELECT
|
|
c.task_inserted_at,
|
|
c.task_id,
|
|
c.task_retry_count
|
|
FROM
|
|
slots_to_cancel c
|
|
)
|
|
)
|
|
SELECT
|
|
*,
|
|
'SCHEDULING_TIMED_OUT' AS "operation"
|
|
FROM
|
|
schedule_timeout_slots
|
|
UNION ALL
|
|
SELECT
|
|
*,
|
|
'CANCELLED' AS "operation"
|
|
FROM
|
|
slots_to_cancel
|
|
WHERE
|
|
-- not in the schedule_timeout_slots
|
|
(task_inserted_at, task_id, task_retry_count) NOT IN (
|
|
SELECT
|
|
c.task_inserted_at,
|
|
c.task_id,
|
|
c.task_retry_count
|
|
FROM
|
|
schedule_timeout_slots c
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
*,
|
|
'RUNNING' AS "operation"
|
|
FROM
|
|
updated_slots;
|
|
|
|
-- name: RunCancelInProgress :many
|
|
WITH slots AS (
|
|
SELECT
|
|
task_id,
|
|
task_inserted_at,
|
|
task_retry_count,
|
|
tenant_id,
|
|
strategy_id,
|
|
key,
|
|
is_filled,
|
|
-- Order slots by rn desc, seqnum desc to ensure that the most recent tasks will be run
|
|
row_number() OVER (PARTITION BY key ORDER BY sort_id DESC) AS rn,
|
|
row_number() OVER (ORDER BY sort_id DESC) AS seqnum
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid AND
|
|
strategy_id = @strategyId::bigint AND
|
|
(
|
|
schedule_timeout_at >= NOW() OR
|
|
is_filled = TRUE
|
|
)
|
|
), schedule_timeout_slots AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid AND
|
|
strategy_id = @strategyId::bigint AND
|
|
schedule_timeout_at < NOW() AND
|
|
is_filled = FALSE
|
|
), eligible_running_slots AS (
|
|
SELECT
|
|
task_id,
|
|
task_inserted_at,
|
|
task_retry_count,
|
|
tenant_id,
|
|
strategy_id,
|
|
key,
|
|
is_filled,
|
|
rn,
|
|
seqnum
|
|
FROM
|
|
slots
|
|
WHERE
|
|
rn <= @maxRuns::int
|
|
), slots_to_cancel AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid AND
|
|
strategy_id = @strategyId::bigint AND
|
|
(task_inserted_at, task_id, task_retry_count) NOT IN (
|
|
SELECT
|
|
ers.task_inserted_at,
|
|
ers.task_id,
|
|
ers.task_retry_count
|
|
FROM
|
|
eligible_running_slots ers
|
|
)
|
|
ORDER BY
|
|
task_id, task_inserted_at
|
|
FOR UPDATE
|
|
), slots_to_run AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count, tenant_id, strategy_id) IN (
|
|
SELECT
|
|
ers.task_inserted_at,
|
|
ers.task_id,
|
|
ers.task_retry_count,
|
|
ers.tenant_id,
|
|
ers.strategy_id
|
|
FROM
|
|
eligible_running_slots ers
|
|
ORDER BY
|
|
rn, seqnum
|
|
)
|
|
ORDER BY
|
|
task_id, task_inserted_at
|
|
FOR UPDATE
|
|
), updated_slots AS (
|
|
UPDATE
|
|
v1_concurrency_slot
|
|
SET
|
|
is_filled = TRUE
|
|
FROM
|
|
slots_to_run
|
|
WHERE
|
|
v1_concurrency_slot.task_id = slots_to_run.task_id AND
|
|
v1_concurrency_slot.task_inserted_at = slots_to_run.task_inserted_at AND
|
|
v1_concurrency_slot.task_retry_count = slots_to_run.task_retry_count AND
|
|
v1_concurrency_slot.key = slots_to_run.key AND
|
|
v1_concurrency_slot.is_filled = FALSE
|
|
RETURNING
|
|
v1_concurrency_slot.*
|
|
), deleted_slots AS (
|
|
DELETE FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count) IN (
|
|
SELECT
|
|
c.task_inserted_at,
|
|
c.task_id,
|
|
c.task_retry_count
|
|
FROM
|
|
slots_to_cancel c
|
|
)
|
|
)
|
|
SELECT
|
|
*,
|
|
'SCHEDULING_TIMED_OUT' AS "operation"
|
|
FROM
|
|
schedule_timeout_slots
|
|
UNION ALL
|
|
SELECT
|
|
*,
|
|
'CANCELLED' AS "operation"
|
|
FROM
|
|
slots_to_cancel
|
|
WHERE
|
|
-- not in the schedule_timeout_slots
|
|
(task_inserted_at, task_id, task_retry_count) NOT IN (
|
|
SELECT
|
|
c.task_inserted_at,
|
|
c.task_id,
|
|
c.task_retry_count
|
|
FROM
|
|
schedule_timeout_slots c
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
*,
|
|
'RUNNING' AS "operation"
|
|
FROM
|
|
updated_slots;
|
|
|
|
-- name: RunParentCancelNewest :exec
|
|
WITH eligible_running_slots AS (
|
|
SELECT wsc.*
|
|
FROM (
|
|
SELECT DISTINCT key
|
|
FROM tmp_workflow_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid
|
|
AND strategy_id = @strategyId::bigint
|
|
) distinct_keys
|
|
JOIN LATERAL (
|
|
SELECT *
|
|
FROM tmp_workflow_concurrency_slot wcs_all
|
|
WHERE
|
|
wcs_all.key = distinct_keys.key
|
|
AND wcs_all.tenant_id = @tenantId::uuid
|
|
AND wcs_all.strategy_id = @strategyId::bigint
|
|
ORDER BY wcs_all.sort_id ASC
|
|
LIMIT @maxRuns::int
|
|
) wsc ON true
|
|
), slots_to_run AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_workflow_concurrency_slot
|
|
WHERE
|
|
(strategy_id, workflow_version_id, workflow_run_id) IN (
|
|
SELECT
|
|
ers.strategy_id,
|
|
ers.workflow_version_id,
|
|
ers.workflow_run_id
|
|
FROM
|
|
eligible_running_slots ers
|
|
)
|
|
ORDER BY
|
|
strategy_id, workflow_version_id, workflow_run_id
|
|
FOR UPDATE
|
|
), update_tmp_table AS (
|
|
UPDATE
|
|
tmp_workflow_concurrency_slot wsc
|
|
SET
|
|
is_filled = TRUE
|
|
FROM
|
|
slots_to_run
|
|
WHERE
|
|
wsc.strategy_id = slots_to_run.strategy_id AND
|
|
wsc.workflow_version_id = slots_to_run.workflow_version_id AND
|
|
wsc.workflow_run_id = slots_to_run.workflow_run_id
|
|
)
|
|
UPDATE
|
|
v1_workflow_concurrency_slot wsc
|
|
SET
|
|
is_filled = TRUE
|
|
FROM
|
|
slots_to_run sr
|
|
WHERE
|
|
wsc.strategy_id = sr.strategy_id AND
|
|
wsc.workflow_version_id = sr.workflow_version_id AND
|
|
wsc.workflow_run_id = sr.workflow_run_id;
|
|
|
|
-- name: RunChildCancelNewest :many
|
|
WITH slots AS (
|
|
SELECT
|
|
task_id,
|
|
task_inserted_at,
|
|
task_retry_count,
|
|
cs.tenant_id,
|
|
cs.strategy_id,
|
|
cs.key,
|
|
cs.is_filled,
|
|
-- Order slots by rn desc, seqnum desc to ensure that the most recent tasks will be run
|
|
row_number() OVER (PARTITION BY cs.key ORDER BY cs.sort_id ASC) AS rn,
|
|
row_number() OVER (ORDER BY cs.sort_id ASC) AS seqnum
|
|
FROM
|
|
v1_concurrency_slot cs
|
|
JOIN
|
|
tmp_workflow_concurrency_slot wcs ON (wcs.strategy_id, wcs.workflow_version_id, wcs.workflow_run_id) = (cs.parent_strategy_id, cs.workflow_version_id, cs.workflow_run_id)
|
|
WHERE
|
|
cs.tenant_id = @tenantId::uuid AND
|
|
cs.strategy_id = @strategyId::bigint AND
|
|
(
|
|
cs.parent_strategy_id IS NULL OR
|
|
wcs.is_filled = TRUE
|
|
) AND
|
|
(
|
|
schedule_timeout_at >= NOW() OR
|
|
cs.is_filled = TRUE
|
|
)
|
|
), schedule_timeout_slots AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid AND
|
|
strategy_id = @strategyId::bigint AND
|
|
schedule_timeout_at < NOW() AND
|
|
is_filled = FALSE
|
|
), eligible_running_slots AS (
|
|
SELECT
|
|
task_id,
|
|
task_inserted_at,
|
|
task_retry_count,
|
|
tenant_id,
|
|
strategy_id,
|
|
key,
|
|
is_filled,
|
|
rn,
|
|
seqnum
|
|
FROM
|
|
slots
|
|
WHERE
|
|
rn <= @maxRuns::int
|
|
), slots_to_cancel AS (
|
|
SELECT
|
|
cs.*
|
|
FROM
|
|
v1_concurrency_slot cs
|
|
JOIN
|
|
tmp_workflow_concurrency_slot wcs ON (wcs.strategy_id, wcs.workflow_version_id, wcs.workflow_run_id) = (cs.parent_strategy_id, cs.workflow_version_id, cs.workflow_run_id)
|
|
WHERE
|
|
cs.tenant_id = @tenantId::uuid AND
|
|
cs.strategy_id = @strategyId::bigint AND
|
|
(cs.task_inserted_at, cs.task_id, cs.task_retry_count) NOT IN (
|
|
SELECT
|
|
ers.task_inserted_at,
|
|
ers.task_id,
|
|
ers.task_retry_count
|
|
FROM
|
|
eligible_running_slots ers
|
|
)
|
|
ORDER BY
|
|
cs.task_id ASC, cs.task_inserted_at ASC
|
|
FOR UPDATE
|
|
), slots_to_run AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count, tenant_id, strategy_id) IN (
|
|
SELECT
|
|
ers.task_inserted_at,
|
|
ers.task_id,
|
|
ers.task_retry_count,
|
|
ers.tenant_id,
|
|
ers.strategy_id
|
|
FROM
|
|
eligible_running_slots ers
|
|
ORDER BY
|
|
rn, seqnum
|
|
)
|
|
ORDER BY
|
|
task_id ASC, task_inserted_at ASC
|
|
FOR UPDATE
|
|
), updated_slots AS (
|
|
UPDATE
|
|
v1_concurrency_slot
|
|
SET
|
|
is_filled = TRUE
|
|
FROM
|
|
slots_to_run
|
|
WHERE
|
|
v1_concurrency_slot.task_id = slots_to_run.task_id AND
|
|
v1_concurrency_slot.task_inserted_at = slots_to_run.task_inserted_at AND
|
|
v1_concurrency_slot.task_retry_count = slots_to_run.task_retry_count AND
|
|
v1_concurrency_slot.key = slots_to_run.key AND
|
|
v1_concurrency_slot.is_filled = FALSE
|
|
RETURNING
|
|
v1_concurrency_slot.*
|
|
), deleted_slots AS (
|
|
DELETE FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count) IN (
|
|
SELECT
|
|
c.task_inserted_at,
|
|
c.task_id,
|
|
c.task_retry_count
|
|
FROM
|
|
slots_to_cancel c
|
|
)
|
|
)
|
|
SELECT
|
|
*,
|
|
'SCHEDULING_TIMED_OUT' AS "operation"
|
|
FROM
|
|
schedule_timeout_slots
|
|
UNION ALL
|
|
SELECT
|
|
*,
|
|
'CANCELLED' AS "operation"
|
|
FROM
|
|
slots_to_cancel
|
|
WHERE
|
|
-- not in the schedule_timeout_slots
|
|
(task_inserted_at, task_id, task_retry_count) NOT IN (
|
|
SELECT
|
|
c.task_inserted_at,
|
|
c.task_id,
|
|
c.task_retry_count
|
|
FROM
|
|
schedule_timeout_slots c
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
*,
|
|
'RUNNING' AS "operation"
|
|
FROM
|
|
updated_slots;
|
|
|
|
-- name: RunCancelNewest :many
|
|
WITH slots AS (
|
|
SELECT
|
|
task_id,
|
|
task_inserted_at,
|
|
task_retry_count,
|
|
cs.tenant_id,
|
|
cs.strategy_id,
|
|
cs.key,
|
|
cs.is_filled,
|
|
-- Order slots by rn desc, seqnum desc to ensure that the most recent tasks will be run
|
|
row_number() OVER (PARTITION BY cs.key ORDER BY cs.sort_id ASC) AS rn,
|
|
row_number() OVER (ORDER BY cs.sort_id ASC) AS seqnum
|
|
FROM
|
|
v1_concurrency_slot cs
|
|
WHERE
|
|
cs.tenant_id = @tenantId::uuid AND
|
|
cs.strategy_id = @strategyId::bigint AND
|
|
(
|
|
schedule_timeout_at >= NOW() OR
|
|
cs.is_filled = TRUE
|
|
)
|
|
), schedule_timeout_slots AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid AND
|
|
strategy_id = @strategyId::bigint AND
|
|
schedule_timeout_at < NOW() AND
|
|
is_filled = FALSE
|
|
), eligible_running_slots AS (
|
|
SELECT
|
|
task_id,
|
|
task_inserted_at,
|
|
task_retry_count,
|
|
tenant_id,
|
|
strategy_id,
|
|
key,
|
|
is_filled,
|
|
rn,
|
|
seqnum
|
|
FROM
|
|
slots
|
|
WHERE
|
|
rn <= @maxRuns::int
|
|
), slots_to_cancel AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
tenant_id = @tenantId::uuid AND
|
|
strategy_id = @strategyId::bigint AND
|
|
(task_inserted_at, task_id, task_retry_count) NOT IN (
|
|
SELECT
|
|
ers.task_inserted_at,
|
|
ers.task_id,
|
|
ers.task_retry_count
|
|
FROM
|
|
eligible_running_slots ers
|
|
)
|
|
ORDER BY
|
|
task_id ASC, task_inserted_at ASC
|
|
FOR UPDATE
|
|
), slots_to_run AS (
|
|
SELECT
|
|
*
|
|
FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count, tenant_id, strategy_id) IN (
|
|
SELECT
|
|
ers.task_inserted_at,
|
|
ers.task_id,
|
|
ers.task_retry_count,
|
|
ers.tenant_id,
|
|
ers.strategy_id
|
|
FROM
|
|
eligible_running_slots ers
|
|
ORDER BY
|
|
rn, seqnum
|
|
)
|
|
ORDER BY
|
|
task_id ASC, task_inserted_at ASC
|
|
FOR UPDATE
|
|
), updated_slots AS (
|
|
UPDATE
|
|
v1_concurrency_slot
|
|
SET
|
|
is_filled = TRUE
|
|
FROM
|
|
slots_to_run
|
|
WHERE
|
|
v1_concurrency_slot.task_id = slots_to_run.task_id AND
|
|
v1_concurrency_slot.task_inserted_at = slots_to_run.task_inserted_at AND
|
|
v1_concurrency_slot.task_retry_count = slots_to_run.task_retry_count AND
|
|
v1_concurrency_slot.key = slots_to_run.key AND
|
|
v1_concurrency_slot.is_filled = FALSE
|
|
RETURNING
|
|
v1_concurrency_slot.*
|
|
), deleted_slots AS (
|
|
DELETE FROM
|
|
v1_concurrency_slot
|
|
WHERE
|
|
(task_inserted_at, task_id, task_retry_count) IN (
|
|
SELECT
|
|
c.task_inserted_at,
|
|
c.task_id,
|
|
c.task_retry_count
|
|
FROM
|
|
slots_to_cancel c
|
|
)
|
|
)
|
|
SELECT
|
|
*,
|
|
'SCHEDULING_TIMED_OUT' AS "operation"
|
|
FROM
|
|
schedule_timeout_slots
|
|
UNION ALL
|
|
SELECT
|
|
*,
|
|
'CANCELLED' AS "operation"
|
|
FROM
|
|
slots_to_cancel
|
|
WHERE
|
|
-- not in the schedule_timeout_slots
|
|
(task_inserted_at, task_id, task_retry_count) NOT IN (
|
|
SELECT
|
|
c.task_inserted_at,
|
|
c.task_id,
|
|
c.task_retry_count
|
|
FROM
|
|
schedule_timeout_slots c
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
*,
|
|
'RUNNING' AS "operation"
|
|
FROM
|
|
updated_slots;
|