towerops/vendor/oban_pro/usage-rules/plugins.md
Graham McIntire 6c05d45dd6 deps: upgrade oban_pro to 1.7.0
Bumps vendored Oban Pro from 1.6.13 to 1.7.0, which transitively bumps
oban core to 2.22.1 (requires migrations v14) and db_connection to 2.10.0.

- mix.exs constraint: ~> 1.6 → ~> 1.7
- vendor/oban_pro/ replaced with v1.7.0 hex package
- migration 20260430142200: Oban core v12 → v14 (must run first)
- migration 20260430142241: Oban Pro 1.7.0 schema additions

Also corrects a pre-existing constraint name in AgentAssignment that was
left stale by the equipment→devices rename migration (20260117190134).
The unique index is named agent_assignments_device_id_index, but the
schema's unique_constraint/3 still pointed at the old equipment_id name,
causing the test suite to surface Ecto.ConstraintError instead of a
changeset error. Required to get the suite green for this upgrade.
2026-04-30 10:26:18 -05:00

6.7 KiB

Plugins

Available Plugins

  • DynamicCron: Runtime-configurable cron scheduling with cluster-wide coordination
  • DynamicLifeline: Rescues orphaned jobs, repairs stuck workflows/chains
  • DynamicPrioritizer: Automatically increases priority of waiting jobs
  • DynamicPruner: Flexible job retention with per-queue/worker rules
  • DynamicQueues: Persists queue configuration across restarts
  • DynamicScaler: Auto-scales cloud infrastructure based on queue depth

DynamicCron

Runtime-configurable cron with cluster-wide coordination. Unlike standard Oban cron, DynamicCron supports runtime updates, guaranteed scheduling, and automatic sync.

Configuration

{Oban.Pro.Plugins.DynamicCron,
 timezone: "Etc/UTC",
 sync_mode: :automatic,
 crontab: [
   {"*/5 * * * *", MyApp.Workers.FrequentWorker},
   {"0 0 * * *", MyApp.Workers.DailyWorker, guaranteed: true},
   {"0 9 * * MON", MyApp.Workers.WeeklyWorker, timezone: "America/New_York"},
   {"@reboot", MyApp.Workers.StartupWorker}
 ]}

Options

  • timezone — default timezone for all entries (defaults to "Etc/UTC")
  • sync_mode:automatic syncs crontab entries to the database on startup, removing stale entries; :manual requires explicit insert/1 and delete/1 calls
  • guaranteed — per-entry option that ensures missed jobs are inserted when the system comes back online (use for critical scheduled tasks)

Runtime Management

alias Oban.Pro.Plugins.DynamicCron

# Insert or update entries at runtime
DynamicCron.insert({"0 * * * *", MyApp.HourlyWorker})

# Delete an entry
DynamicCron.delete(MyApp.HourlyWorker)

# Get an entry's details
DynamicCron.get(MyApp.HourlyWorker)

# List all entries
DynamicCron.all()

DynamicLifeline

Rescues orphaned jobs and repairs stuck workflows and chains. Essential for production systems where nodes may crash or restart unexpectedly.

Configuration

{Oban.Pro.Plugins.DynamicLifeline, retry_discarded: false}

Options

  • retry_discarded — whether to retry discarded workflow/chain jobs when dependencies complete

Do not change the rescue_interval option. If you see it configured, remove it—the default is carefully tuned and changing it causes problems.

What It Rescues

  • Orphaned jobs — jobs stuck in executing state after a node crash
  • Stuck workflows — workflows blocked by completed dependencies that weren't properly tracked
  • Stuck chains — chains that stopped progressing due to missed completion signals
  • Partition backfill — repopulates rate limit and global limit partitions after restarts

DynamicPrioritizer

Automatically increases priority of jobs that have been waiting too long. Prevents starvation of low-priority jobs in busy systems.

Configuration

{Oban.Pro.Plugins.DynamicPrioritizer,
 prioritizers: [
   rate: [queue: :default, rate: 1, period: to_timeout(second: 30)],
   once: [queue: :media, threshold: to_timeout(minute: 5), boost: 1]
 ]}

Strategies

  • rate — continuously boost priority at a fixed rate while waiting
  • once — boost priority once after a threshold wait time

Options

  • queue — target queue (required)
  • rate — priority boost per period (for rate strategy)
  • period — how often to apply the boost (for rate strategy)
  • threshold — wait time before boosting (for once strategy)
  • boost — how much to increase priority (for once strategy, default: 1)

DynamicPruner

Flexible job retention with per-queue and per-worker rules. More powerful than the standard Oban pruner with fine-grained control over what gets deleted and when.

Configuration

{Oban.Pro.Plugins.DynamicPruner,
 mode: {:max_age, {7, :days}},
 queue_overrides: [
   logs: {:max_age, {1, :day}},
   critical: {:max_age, {30, :days}}
 ],
 worker_overrides: [
   MyApp.AuditWorker: {:max_age, {90, :days}},
   MyApp.TempWorker: {:max_age, {1, :hour}}
 ]}

Modes

  • {:max_age, {count, unit}} — delete jobs older than the specified age
  • {:max_length, count} — keep only the most recent N jobs

Options

  • mode — default retention rule for all jobs
  • queue_overrides — per-queue retention rules
  • worker_overrides — per-worker retention rules (takes precedence over queue rules)
  • state — which job states to prune (default: [:completed, :cancelled, :discarded])

DynamicQueues

Persists queue configuration to the database for runtime management. Queues survive restarts and can be modified without redeploying.

Configuration

{Oban.Pro.Plugins.DynamicQueues,
 sync_mode: :automatic,
 queues: [
   default: 10,
   mailers: [local_limit: 20, rate_limit: [allowed: 100, period: {1, :minute}]],
   exports: [local_limit: 5, only: {:node, :=~, "worker"}]
 ]}

Options

  • sync_mode:automatic syncs queue config to database on startup; :manual requires explicit API calls
  • queues — initial queue definitions (same format as standard Oban queues)
  • only — restrict queue to matching nodes using {:node, pattern} or {:sys_env, key, pattern}; supports operators :==, :!=, :=~ for pattern matching

Runtime Management

alias Oban.Pro.Plugins.DynamicQueues

# Add or update a queue
DynamicQueues.insert(:reports, local_limit: 5)

# Pause a queue
DynamicQueues.pause(:reports)

# Resume a queue
DynamicQueues.resume(:reports)

# Scale a queue
DynamicQueues.scale(:reports, local_limit: 20)

# Delete a queue
DynamicQueues.delete(:reports)

# List all queues
DynamicQueues.all()

DynamicScaler

Auto-scales cloud infrastructure based on queue depth and throughput. Scales nodes horizontally to optimize processing during high traffic and save costs during quiet periods.

Configuration

{Oban.Pro.Plugins.DynamicScaler,
 scalers: [
   range: 1..5,
   cloud: MyApp.Cloud
 ]}

Options

  • cloud — module implementing the Oban.Pro.Cloud behaviour (required)
  • range — min..max nodes to scale between (required)
  • cooldown — minimum time between scaling events (default: 120 seconds)
  • queues:all or list of queues to monitor (default: :all)
  • step:none or max nodes to scale at once (default: :none)

Features

  • Predictive scaling — calculates optimal scale based on recent trends, not just current depth
  • Multi-cloud — implement the Cloud behaviour for your platform (AWS, Fly, Kubernetes, etc.)
  • Thrashing prevention — cooldown period prevents rapid scale up/down cycles

Cloud Behaviour

Implement Oban.Pro.Cloud for your platform:

defmodule MyApp.Cloud do
  @behaviour Oban.Pro.Cloud

  @impl true
  def init(opts), do: opts

  @impl true
  def current(_opts), do: {:ok, current_node_count()}

  @impl true
  def scale(count, _opts), do: scale_to(count)
end