mirror of
https://github.com/block/buzz.git
synced 2026-11-02 15:31:27 +00:00
The scheduled-workflow fire path never called the durable claim primitives (`claim_scheduled_workflow_fire` had zero callers outside the DB wrappers and tests), so with N relay pods every pod that saw a due cron/interval row created a run and executed the side effect — a multi-pod duplicate-run bug. And the claim primitive itself was still keyed by bare `workflow_id` (`WHERE w.id = $1`) despite the schema's `(community_id, id)` workflow identity: with duplicate workflow UUIDs across communities (which the schema explicitly allows and the Issue-4 confinement tests pin), a single `INSERT ... SELECT` matched every community's row and fanned one claim across all of them. Scope the claim to its community and wire the claim->run boundary into the scheduler: - `claim_scheduled_workflow_fire` takes `CommunityId` and binds `WHERE w.community_id = $1 AND w.id = $2`. The community is server provenance — the `workflow.community_id` from the global scan, never client input. This reverses the earlier S1 "resolve-from-id-alone" lock, which was written against a globally-unique-`workflow_id` assumption the final `(community_id, id)` schema does not hold (and which is unimplementable on that key). The surviving invariant is "the claim community is server provenance, not client-controlled." - `WorkflowEngine::run` now claims before `create_workflow_run`; the loser skips before any run creation or side effect. The claim anchor `scheduled_for` is deterministic across pods: the cron's own scheduled instant (`cron_fire_instant`, not `now`) or the interval bucket boundary (`interval_fire_instant`, floor to the interval). The interval anchor is seeded from `latest_scheduled_workflow_fire` on the first tick after restart so a process bounce can't double-fire within an interval. `attach_scheduled_workflow_run` links the won claim to its run for ops/audit forensics. Tests: - Rewrite the stale S1 comment block and `claim_for_workflow_in_other_ community_no_ops` (which encoded the now-false globally-unique assumption) into `claim_confined_to_its_community`: a dup workflow UUID in A and B claims independently (claiming A/id leaves B/id claimable). Proven RED on the bare-`id` regression. - `concurrent_same_window_claims_exactly_one_wins` and the prune-anchor test updated to the scoped signature. - New `cron_fire_instant` / `interval_fire_instant` unit tests pin the deterministic, drift-stable claim anchors. Full `cargo test -p buzz-db -p buzz-workflow -p buzz-relay` green vs live Postgres (serial); clippy clean on the trio. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>