I want an Oban worker which runs periodically (e.g. every hour), but should be unique, so if the worker takes longer than the period between runs another worker is not enqueued.
I have an Elixir cluster with Oban Pro.
I’m using the Cron plug configured as such:
config :shared, Oban,
engine: Oban.Pro.Engines.Smart,
queues: [exports: 1],
repo: Shared.Infrastructure.Repo,
plugins: [
{
Oban.Plugins.Cron,
crontab: [
# every min for testing purposes
{"* * * * *", Export.Standard.Worker}
]
}
]
My first native approach was this:
use Oban.Pro.Worker,
queue: :exports,
unique: :infinity
However this means the worker only ever runs once since it accepts no arguments, so the unique fields, worker, queue and arg’s, are always the same, and given the time period is infinity it never runs again.
So I tried adding in the states:
use Oban.Pro.Worker,
queue: :exports,
unique: [period: :infinity, states: [:available, :executing]]
Then I tried removing the unique
and setting global_limit
for the queue to 1
, this means only one worker can run at once.
config :shared, Oban,
engine: Oban.Pro.Engines.Smart,
queues: [
exports: [global_limit: 1]
],
repo: Shared.Infrastructure.Repo,
plugins: [
{
Oban.Plugins.Cron,
crontab: [
# every min for testing purposes
{"* * * * *", Export.Standard.Worker}
]
}
]
use Oban.Pro.Worker,
queue: :exports
This seems to work well enough.
But I do notice however that I accumulate a lot of jobs in “available” state, I think this is because cron starts the worker but can’t run it because of the global_limit of 1. So they build up indefinitely.
Is there anything I’m missing or a better approach to this perhaps?