Baton.Retention (Baton v0.27.4)

Copy Markdown View Source

Deletes Baton's own rows once the Oban job they belong to is gone.

Baton's tables (workflow_nodes, workflow_step_stats, workflow_debug_logs, workflow_completions) carry no foreign key to oban_jobs — Oban owns that table and prunes it on its own schedule. Without cleanup, every workflow ever run would leave permanent rows here.

This module piggybacks on Oban's Pruner: a row is considered dead once its backing oban_jobs row has been pruned. Baton.Plugin calls delete_orphans/2 on its sweep when pruning is enabled.

Safety

A node/stat row is deleted only when its own job is gone, and Oban only prunes jobs that are already terminal (completed/cancelled/discarded) and past its max_age. As long as that max_age exceeds your longest workflow's runtime — which Baton already requires for correct dependency gating — this never removes data a still-running workflow depends on.

Deletes are bounded by limit per call so a large backlog is worked down across several sweeps rather than in one long transaction.

Summary

Functions

Delete up to limit orphaned rows from each Baton table. Returns a map of table => deleted_count.

Permanently delete one workflow: cancel any of its still-live Oban jobs, then remove every row it owns across Baton's tables and oban_jobs.

Functions

delete_orphans(repo, limit)

@spec delete_orphans(module(), pos_integer()) :: %{
  required(atom()) => non_neg_integer()
}

Delete up to limit orphaned rows from each Baton table. Returns a map of table => deleted_count.

The workflow_artifacts sweep reclaims storage for the built-in Postgres backend. Custom backends are responsible for reclaiming their own storage when a job is pruned; delete_workflow/2 calls their delete/1 for explicit run deletion.

delete_workflow(workflow_id, opts \\ [])

@spec delete_workflow(
  String.t(),
  keyword()
) :: {:ok, %{required(atom()) => non_neg_integer()}}

Permanently delete one workflow: cancel any of its still-live Oban jobs, then remove every row it owns across Baton's tables and oban_jobs.

Unlike delete_orphans/2 — which only removes rows whose backing job Oban has already pruned — this targets a specific workflow_id whose jobs may still be live, so it cancels them first. Intended for an operator/admin "delete run" action.

Options:

  • :repo — Ecto repo (default: resolved from Oban config)
  • :oban — Oban instance name (default: Baton.Config.oban_name/0)

Returns {:ok, %{table => deleted_count}}.