feat(flare-workflow): implement saga rollback/compensation handlers - #499
Conversation
Implements item #118's approved design (ROLLBACK_COMPENSATION_DESIGN.md, carried over from the unmerged design PR): StepDefinition::with_rollback registers a compensation handler on Sequential/FanOut/Loop steps, rejected at register_workflow time on unsupported modes via ValidationError::RollbackUnsupportedMode. On workflow failure, a new rollback phase (src/rollback.rs) unwinds every succeeded step with a registered handler in reverse step-start order, reconstructing each handler's context from that step's own journaled StepRun snapshot (the failing step itself runs with an empty output, matching Cloudflare's `output: undefined` case). Compensation is journaled via a new JournalEntry::Rollback variant for exactly-once resumption across a crash mid-unwind, and is best-effort: a handler that exhausts its retries is journaled as failed and the sweep continues rather than aborting. Both existing failure-settlement points in execute_workflow are consolidated into one finish_workflow_failed helper that runs the rollback phase before flipping status to Failed, keeping status at Running throughout the unwind so recover() naturally resumes a crashed rollback with no new status variant needed. Loop's terminal StepRun entry now journals the full serialized context (matching Sequential/FanOut) instead of just the raw output string, since rollback context reconstruction depends on that snapshot existing for all three supported modes. Agentflare-Agent: claude-code Agentflare-Branch: task/119-feat-flare-workflow-implement-saga-rollb Agentflare-Item: 119
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 29 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (8)
Comment |
…e match The rollback-support check in WorkflowDefinition::validate() was added by #499 before StepMode::SleepUntil existed on this branch's own #497, so the merge left the match non-exhaustive. SleepUntil journals only a timer marker like Sleep, not a context snapshot, so it's unsupported for rollback the same way. Agentflare-Agent: claude-code Agentflare-Branch: task/117-feat-flare-workflow-durable-sleepuntil-s Agentflare-Item: 117
* feat(flare-workflow): add durable SleepUntil step mode
Add StepMode::SleepUntil { wake_at } alongside the existing relative
Sleep mode, for absolute-timestamp durable delays (Cloudflare Workflows'
step.sleepUntil() equivalent). Both modes now share execute_sleep via a
WakeAt enum that resolves relative-vs-absolute before the existing
journal-and-recover logic runs, so crash recovery keeps reusing the
originally journaled wake_at unchanged.
Agentflare-Agent: claude-code
Agentflare-Branch: task/117-feat-flare-workflow-durable-sleepuntil-s
Agentflare-Item: 117
* fix(flare-workflow): cover SleepUntil in the rollback-unsupported-mode match
The rollback-support check in WorkflowDefinition::validate() was added
by #499 before StepMode::SleepUntil existed on this branch's own #497,
so the merge left the match non-exhaustive. SleepUntil journals only a
timer marker like Sleep, not a context snapshot, so it's unsupported
for rollback the same way.
Agentflare-Agent: claude-code
Agentflare-Branch: task/117-feat-flare-workflow-durable-sleepuntil-s
Agentflare-Item: 117
---------
Co-authored-by: shiva <shiva@gosysinfo.tech>
Everything is clean:
cargo fmt --checkpasses,cargo clippy -D warningsis clean, and all 62 tests pass (including the 4 new rollback tests), with the LOC gate hook accepting the commit.Summary
Implemented saga rollback/compensation for
crates/flare-workflowper item #118's approved design doc (which lived only on the unmergedtask/118branch — copied it into this branch since neither #117 nor #118 had landed on master yet, matching the item's own rebase-instruction fallback).Changes:
types.rs: newJournalEntry::Rollback { step_id, attempt, result }variant with matchingis_completed/entry_typearms.definition.rs:StepDefinition.rollback/rollback_retry_policyfields,with_rollback()builder,ValidationError::RollbackUnsupportedModerejected invalidate()forCollect/Conditional/Sleep/WaitEvent.events.rs: newWorkflowEvent::RollbackCompleted/RollbackStepFailed.src/rollback.rs(new):run_rollback_phase— reverse-start-order unwind, context reconstruction from each step's journaledStepRunsnapshot (empty output for the triggering failed step), retry via the existingBackoff/apply_jittermachinery, best-effort continue-on-exhaustion, exactly-once resumption via completedRollbackentries.engine.rs: newfinish_workflow_failedhelper consolidating both failure-settlement points, running rollback before flipping status toFailed(status staysRunningthrough the unwind sorecover()needs no special-casing). Also fixedexecute_loop's terminal journal entry to store the full serialized context instead of just the raw output string — the design doc assumed Loop already did this, but master's code didn't, which would have broken rollback context reconstruction for Loop steps.tests/rollback_test.rs(new): all 6 acceptance-criteria scenarios (a)-(f), including a crash-mid-rollback +recover()test proving exactly-once compensation.Committed as
840ef6c.