Update Oban Job's scheduled_at time

I have an Elixir app that uses Oban to schedule jobs at a time specified by users. For example, users can specify the date and time to send a certain email.

Oban works great at scheduling the job initially, and with other features like uniqueness, but I can’t find a sensible way to update the scheduled time of an existing job (when the user wants to change the time).

Currently, two approaches come to mind:

1. Cancel job and queue again

job =
  Oban.Job
  |> where(fragment("args->>'task_id'") == ^task_id)
  |> where([j], j.state in ~w[available scheduled])
  |> Repo.one()

Oban.cancel_job(TaskWorker, job.id)

job.args
|> TaskWorker.new(schedule_at: new_time)
|> Oban.insert()

2. Update job manually

Oban.Job
|> where(fragment("args->>'task_id'") == ^task_id)
|> where([j], j.state in ~w[available scheduled])
|> Repo.one()
|> Ecto.Changeset.cast(%{scheduled_at: new_time}, [:scheduled_at])
|> Repo.update()

But I worry that Oban might have its own hooks which do not get called when updating manually or if there’s a better way to do this.

Also posted on Stackoverflow:

2 Likes

I would go with option 1, cancel and re-insert. A lot cleaner that way and will work in future versions of Oban also.

Note that a lot of support for Oban and other Elixir packages also happens in realtime on Slack.

As of a recent (and unreleased) PR, there is built in support for this exact situation:

3 Likes

That looks like exactly what I need. Any ETA on when you’re planning to publish a new release with this?

Very soon, possibly today :slightly_smiling_face:

3 Likes