Workflow releases
Treat a workflow name as an immutable production target. Console edits write Draft. Live traffic runs the published revision.
This feature is gated by workflow_releases_enabled (default off). With the flag off, API execution still uses the mutable workflow row. Create and import still write revision r1 so backfill stays idempotent. Do not enable the flag in production until the checklist below is complete.
Concepts
| Term | Meaning |
|---|---|
| Draft | Current workflows / workflow_events rows |
| Live | workflows.published_revision_id |
snapshot_hash | Dedup hash (content_hash column); includes child Live pins; excludes structure id/name |
content_fingerprint | Dirty hash; ignores pin revision fields and structure id/name |
| Execution snapshot | Short-lived Draft pin for async playground jobs (not a revision) |
Dirty reasons are independent:
draft_content_changed— Draft fingerprint differs from Livedependency_live_moved— a callback target's Live pin moved
Runtime
- Production keys always run Live. There is no
@12or header pin. - Live async jobs store
workflow_revision_id. - Playground Draft async jobs persist an execution snapshot and store
execution_snapshot_id. The row is kept untilexpires_athas passed and no pending channel and no incomplete Oban job references it. - Deactivating a child does not break existing pins.
by_name404s inactive workflows. New Publish cannot pin an inactive target.
Console
- Name cannot be changed after create.
- Delete deactivates the workflow; revision history and Live pins stay on that row. The name can be reused by a new active workflow in the same project. Production
by_namelookup only matches the active row. - Publish and rollback: organization owner/admin.
- Restore draft: editors; relinks the original structured output when its schema still matches the revision snapshot. Clones only if that structure was edited or deleted, so sibling workflows are untouched.
Enablement
- Run
mix backfill_workflow_releasesuntil zero workflows lack a Live pointer (including inactive workflows). - Confirm callback graphs are acyclic.
- Soak staging with the flag on: queued jobs, channel TTL refresh, Publish during in-flight work.
- Confirm dashboards for
[:modelriver, :workflow, :missing_live]and[:modelriver, :workflow, :execution_snapshot_expired].
Set WORKFLOW_RELEASES_ENABLED=true only after those gates pass.