AuroraMeter.Oban.Retention (Aurora Meter v1.0.0)

View Source

Deletes the disposable operational rows AuroraMeter.Retention allows, in bounded batches.

The work is AuroraMeter.Retention.prune/1 and nothing else. The worker opens no transaction, takes no lock and reads no clock: every cutoff is computed by the database inside the statement that uses it.

config :my_app, Oban,
  plugins: [{Oban.Plugins.Cron, crontab: [
    {"40 3 * * *", AuroraMeter.Oban.Retention}
  ]}]

Recommended schedule "40 3 * * *", which is what AuroraMeter.Oban.cron_entries/1 returns. Nothing depends on the frequency for correctness: a row that is still eligible tomorrow is deleted tomorrow.

Do not schedule this until every node writes a heartbeat

A flush receipt is deleted only when every node's "flush:<node>" heartbeat proves no node can still retry a batch from before the cutoff, and a fleet that has not been upgraded yet writes none. Deploy first, confirm one row per node with AuroraMeter.Retention.status/0, then add the crontab entry. AuroraMeter.Retention refuses rather than guessing if you do it in the other order, which is the safe direction, but the refusal is easier to read before it is a surprise.

Job arguments

KeyDefaultMeaning
"only"every allow-list tableWhich tables to consider, by name. Narrows; never widens.
"batch_size"1000Rows per DELETE statement.
"max_items"50000Rows one job removes per table before returning.

Every one is a bounded integer or an allow-list name, and neither a cursor nor a cutoff is a job argument. "only" is validated against the allow list by AuroraMeter.Retention, so a name outside it fails the job rather than widening what may be deleted.

Pausing

AuroraMeter.Operations.pause("retention:flush_receipts")
AuroraMeter.Operations.pause("retention:replay_checkpoints")

One operation per table, because pausing receipt pruning while leaving the replay rows alone is a thing an operator actually wants. A paused table is reported as a :paused reason and the job still returns {:ok, report}: the other tables were pruned, and a pause is not a failure to retry.

Running it twice

Harmless. A DELETE is idempotent: the second run's statement finds the rows gone and removes nothing. There is no cursor to get stale, because the scan advances by doing the work rather than by remembering a position.

Without Oban, call AuroraMeter.Retention.prune/1 from whatever scheduler you do have. See the scheduler map and Retention.

Summary

Functions

The checkpoint names this worker pauses and resumes under, one per table.

Prunes and returns {:ok, report}.

Functions

operations()

@spec operations() :: [String.t()]

The checkpoint names this worker pauses and resumes under, one per table.

Examples

iex> AuroraMeter.Oban.Retention.operations()
["retention:flush_receipts", "retention:replay_checkpoints"]

perform(job)

@spec perform(Oban.Job.t()) :: {:ok, term()} | {:error, term()} | {:cancel, term()}

Prunes and returns {:ok, report}.

{:ok, {:blocked, report, reasons}} when a table could not be pruned: a node's heartbeat says it may still hold an old batch, or an operator paused the operation. Neither is a failure, so neither fails the job, and both are in the return for an operator reading Oban's completed jobs.

{:error, reason} only when the mechanism itself failed, which Oban retries.

Examples

{:ok, _} = AuroraMeter.Oban.Retention.perform(%Oban.Job{args: %{}})