Skip to main content

ff_backend_sqlite/queries/
claim_grant.rs

1//! SQLite dialect-forked queries for RFC-024 `ff_claim_grant` table.
2//!
3//! Landed by PR-E of the RFC-024 series (SQLite lease-reclaim wiring).
4//! The SQL strings are module-level `const`s so `reclaim.rs` call
5//! sites reference them by name and cross-dialect review lines them
6//! up against the PG reference.
7//!
8//! # Transaction contract
9//!
10//! All callers wrap these statements in a `BEGIN IMMEDIATE` txn per
11//! RFC-023 §4.3 — SQLite's RESERVED lock covers the full read-modify-
12//! write window, so no explicit `FOR UPDATE` equivalent is needed.
13
14/// Read the execution's ownership + phase fields plus the current
15/// reclaim counter. Used by `issue_reclaim_grant_impl` to validate
16/// that the target execution is in a reclaimable state
17/// (`lifecycle_phase = 'active'` AND
18/// `ownership_state IN ('lease_expired_reclaimable', 'lease_revoked')`).
19pub(crate) const SELECT_EXEC_CORE_FOR_RECLAIM_SQL: &str = r#"
20    SELECT lifecycle_phase,
21           ownership_state,
22           eligibility_state,
23           attempt_state,
24           attempt_index,
25           lane_id,
26           lease_reclaim_count
27      FROM ff_exec_core
28     WHERE partition_key = ?1 AND execution_id = ?2
29"#;
30
31/// Insert a reclaim-kind grant row.
32pub(crate) const INSERT_RECLAIM_GRANT_SQL: &str = r#"
33    INSERT INTO ff_claim_grant (
34        partition_key,
35        grant_id,
36        execution_id,
37        kind,
38        worker_id,
39        worker_instance_id,
40        lane_id,
41        capability_hash,
42        worker_capabilities,
43        route_snapshot_json,
44        admission_summary,
45        grant_ttl_ms,
46        issued_at_ms,
47        expires_at_ms
48    ) VALUES (?1, ?2, ?3, 'reclaim', ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)
49"#;
50
51/// Read the reclaim-kind grant row for an execution under a partition.
52pub(crate) const SELECT_RECLAIM_GRANT_BY_EXEC_SQL: &str = r#"
53    SELECT grant_id,
54           worker_id,
55           worker_instance_id,
56           lane_id,
57           expires_at_ms
58      FROM ff_claim_grant
59     WHERE partition_key = ?1 AND execution_id = ?2 AND kind = 'reclaim'
60     ORDER BY issued_at_ms DESC
61     LIMIT 1
62"#;
63
64/// Consume (DELETE) a reclaim grant row.
65pub(crate) const DELETE_RECLAIM_GRANT_SQL: &str = r#"
66    DELETE FROM ff_claim_grant
67     WHERE partition_key = ?1 AND grant_id = ?2
68"#;
69
70/// Reclaim-time re-validation read. Used by
71/// `reclaim_execution_inner` after the grant has been located but
72/// before any state mutation, to defend against:
73///
74/// 1. **Lifecycle/ownership drift between grant issuance and grant
75///    consumption.** The exec may have transitioned to
76///    `terminal`/`cancelled` through another path (e.g. operator
77///    cancel) while the grant was in-flight. Mirrors PG PR-D
78///    `claim_grant.rs::reclaim_execution_once` and Lua
79///    `flowfabric.lua:3049+` gate.
80/// 2. **Caller-supplied stale `current_attempt_index`.** The Rust
81///    API takes this from caller args; a stale value could backward-
82///    pin `attempt_index` or PK-collide with an existing row.
83///    Returning the authoritative value lets the caller derive
84///    `new_attempt_index = stored + 1` server-side.
85/// 3. **Lease-epoch monotonicity.** The prior attempt row's
86///    `lease_epoch` is the floor for the new attempt's epoch
87///    (Lua `next_epoch = current_lease_epoch + 1`). The joined
88///    `ff_attempt.lease_epoch` covers the first-reclaim case where
89///    the `ff_exec_core` lease fields may already be cleared.
90pub(crate) const SELECT_EXEC_CORE_RECLAIM_GATE_SQL: &str = r#"
91    SELECT ec.lease_reclaim_count,
92           ec.lifecycle_phase,
93           ec.ownership_state,
94           ec.attempt_index,
95           COALESCE(a.lease_epoch, 0) AS prior_lease_epoch
96      FROM ff_exec_core ec
97      LEFT JOIN ff_attempt a
98        ON a.partition_key = ec.partition_key
99       AND a.execution_id  = ec.execution_id
100       AND a.attempt_index = ec.attempt_index
101     WHERE ec.partition_key = ?1 AND ec.execution_id = ?2
102"#;
103
104/// Bump `lease_reclaim_count` and flip `ff_exec_core` to the
105/// new-attempt active/leased posture. Mirrors `UPDATE_EXEC_CORE_RECLAIM_SQL`
106/// in `queries/lease.rs` but also bumps `attempt_index` (new attempt)
107/// and `lease_reclaim_count` (RFC-024 §3.3 counter).
108pub(crate) const UPDATE_EXEC_CORE_FOR_NEW_RECLAIM_ATTEMPT_SQL: &str = r#"
109    UPDATE ff_exec_core
110       SET lifecycle_phase = 'active',
111           ownership_state = 'leased',
112           eligibility_state = 'not_applicable',
113           attempt_state = 'running_attempt',
114           attempt_index = ?1,
115           lease_reclaim_count = lease_reclaim_count + 1
116     WHERE partition_key = ?2 AND execution_id = ?3
117"#;
118
119/// Transition `ff_exec_core` to `terminal_failed` on reclaim-cap
120/// exceeded. Mirrors the Lua `max_reclaims_exceeded` branch at
121/// `flowfabric.lua:3049-3080`.
122pub(crate) const UPDATE_EXEC_CORE_RECLAIM_CAP_EXCEEDED_SQL: &str = r#"
123    UPDATE ff_exec_core
124       SET lifecycle_phase = 'terminal',
125           ownership_state = 'unowned',
126           eligibility_state = 'not_applicable',
127           attempt_state = 'attempt_terminal',
128           public_state = 'failed',
129           terminal_at_ms = ?1
130     WHERE partition_key = ?2 AND execution_id = ?3
131"#;
132
133/// Mark the prior attempt as `interrupted_reclaimed`. Mirrors the
134/// Valkey Lua at `flowfabric.lua:3112`.
135pub(crate) const UPDATE_PRIOR_ATTEMPT_INTERRUPTED_RECLAIMED_SQL: &str = r#"
136    UPDATE ff_attempt
137       SET outcome = 'interrupted_reclaimed',
138           terminal_at_ms = ?1
139     WHERE partition_key = ?2 AND execution_id = ?3 AND attempt_index = ?4
140"#;
141
142/// Insert a fresh `ff_attempt` row for the reclaimed attempt. The
143/// `lease_epoch` bind is the caller-derived `prior_lease_epoch + 1`
144/// (see `SELECT_EXEC_CORE_RECLAIM_GATE_SQL`), matching Lua
145/// `flowfabric.lua:3106` (`next_epoch = current_lease_epoch + 1`).
146/// Previous PR-E had this hard-coded to `0`; that broke epoch
147/// monotonicity for lease fencing across the distributed system.
148pub(crate) const INSERT_NEW_RECLAIM_ATTEMPT_SQL: &str = r#"
149    INSERT INTO ff_attempt (
150        partition_key,
151        execution_id,
152        attempt_index,
153        worker_id,
154        worker_instance_id,
155        lease_epoch,
156        lease_expires_at_ms,
157        started_at_ms,
158        policy
159    ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)
160"#;
161
162/// Clear lease fields on the prior attempt row when reclaim
163/// cap-exceeded fires. Mirrors Lua `flowfabric.lua:3064-3079`
164/// (clears `current_lease_id`/`current_worker_*` on exec_core +
165/// DEL on lease_current_key). On SQLite the lease-fencing fields
166/// live on the attempt row, so we clear there and leave the prior
167/// outcome = 'interrupted_reclaimed' for parity with the
168/// successful-reclaim branch.
169pub(crate) const CLEAR_PRIOR_ATTEMPT_LEASE_ON_CAP_EXCEEDED_SQL: &str = r#"
170    UPDATE ff_attempt
171       SET outcome = 'interrupted_reclaimed',
172           terminal_at_ms = ?1,
173           worker_id = NULL,
174           worker_instance_id = NULL,
175           lease_expires_at_ms = NULL
176     WHERE partition_key = ?2 AND execution_id = ?3 AND attempt_index = ?4
177"#;