You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Replace the in-place mutations of workflow_tasks with an
append-only workflow_events log; the existing row becomes the
latest projection. Adds a snapshot policy so replay is bounded,
and a ./scripts/replay-workflow.sh CLI for post-incident
debugging.
Motivation
ROADMAP.md lists "Persist workflow transition history for
audit and replay" as Near Term.
The current mutable row loses information about why a
transition happened (the lease owner, the recovery scheduler's
reasoning, the prior stage, etc.).
Event sourcing is a one-shot investment that unlocks replay, audit
trails, and future analytics projections.
Tasks
V17 migration: workflow_events, workflow_snapshots,
per-task seq index, type-time index for ad-hoc queries.
eventsourcing/workflow/WorkflowEvent.java interface and
nine concrete event records
(Created, LeaseAcquired, LeaseRenewed, StageEntered, Succeeded, Failed, Retried, Recovered, DeadLettered).
Issue 009: Event Sourcing for Workflow State
Summary
Replace the in-place mutations of
workflow_taskswith anappend-only
workflow_eventslog; the existing row becomes thelatest projection. Adds a snapshot policy so replay is bounded,
and a
./scripts/replay-workflow.shCLI for post-incidentdebugging.
Motivation
ROADMAP.mdlists "Persist workflow transition history foraudit and replay" as Near Term.
transition happened (the lease owner, the recovery scheduler's
reasoning, the prior stage, etc.).
trails, and future analytics projections.
Tasks
workflow_events,workflow_snapshots,per-task
seqindex, type-time index for ad-hoc queries.eventsourcing/workflow/WorkflowEvent.javainterface andnine concrete event records
(
Created,LeaseAcquired,LeaseRenewed,StageEntered,Succeeded,Failed,Retried,Recovered,DeadLettered).eventsourcing/workflow/WorkflowEventStore.java(
append,loadSnapshot,replayFrom).eventsourcing/workflow/WorkflowTask.applyEvent(...)as apure-function update on the record.
eventsourcing/workflow/WorkflowTaskProjector.javatransactional consumer that materialises projections.
WorkflowOrchestratorto emit events instead ofmutating
workflow_tasksdirectly.WorkflowRecoverySchedulersimilarly.eventsourcing/workflow/WorkflowSnapshotService.javawiththe policy: 100 events / 5 minutes / any pending change.
scripts/replay-workflow.sh:--since=,--task-id=,--dry-run.docs/operations.md: replay recipes, snapshot retention.cases to drive the event log; add 5 dedicated event-sourcing
ITs.
Acceptance criteria
~10 rows in
workflow_eventsplus an updatedworkflow_tasksprojection.to the prior state by replaying events from the latest
snapshot.
./scripts/replay-workflow.sh --since=2026-08-01T00:00:00Z --task-id=$TASK_ID --dry-runprints the full event sequencefor that task.
/actuator/workflowmetrics continue to work; newfinsight.workflow.eventMeterRegistry timer is exposed.Out of scope
workflow_tasks.References
docs/rfcs/RFC-009-event-sourcing-workflow-state.mdROADMAP.md(Near Term: persist workflow transition history)backend/src/main/java/com/finsight/workflow/WorkflowOrchestrator.java(target of refactor)
backend/src/main/java/com/finsight/workflow/WorkflowRecoveryScheduler.java(target of refactor)
Estimate
8 weeks. Split into 7 PRs:
WorkflowTask.applyEvent+ projector (≈ 600 LoC, 1 PR)WorkflowOrchestratorrefactor (≈ 500 LoC, 1 PR)WorkflowRecoverySchedulerrefactor (≈ 300 LoC, 1 PR)WorkflowSnapshotService+ policy (≈ 400 LoC, 1 PR)LoC, 1 PR)