Skip to content

Instantly share code, notes, and snippets.

@sorentwo
Created August 22, 2022 20:02
Show Gist options
  • Save sorentwo/9fdb54ecd0e78bb0f4e53cb2da68d502 to your computer and use it in GitHub Desktop.
Save sorentwo/9fdb54ecd0e78bb0f4e53cb2da68d502 to your computer and use it in GitHub Desktop.
Guide for inserting Oban jobs from Rails

Migrating background jobs to Elixir is easy with Oban because everything lives in your PostgreSQL database. Oban relies on a structured oban_jobs table as its job queue, and purposefully uses portable data structures (JSON) for serialization. That makes it enqueueing jobs into Oban simple for any language with a PostgreSQL adapter, no Oban client necessary.

As a demonstration, let's explore inserting Oban jobs from a Rails application.

To start, define a skeletal ActiveRecord model with a few conveniences for scheduling jobs:

class Oban::Job < ApplicationRecord
  # This column is in use, but not used for the insert workflow.
  self.ignored_columns = %w[errors]

  # A simple wrapper around `create` that ensures the job is scheduled immediately.
  def self.insert(worker:, args: {}, queue: "default", scheduled_at: nil)
    create(
      worker: worker,
      queue: queue,
      args: args,
      scheduled_at: scheduled_at || Time.now.utc,
      state: scheduled_at ? "scheduled" : "available"
    )
  end
end

The insert class method is a convenience that uses named arguments to force passing a worker while providing some defaults. The only semi-magical thing within insert is determining the correct state for scheduled jobs. In Oban, jobs that are ready to execute have an available state, while jobs slated for the future are scheduled.

To insert a single job using the insert class method:

Oban::Job.insert(worker: "MyWorker", args: {id: 1}, queue: "default")

Provided your Elixir application has a worker named MyWorker and the default queue is running, Oban will pick up and execute the job immediately. To schedule the job to run a minute in the future instead, pass a scheduled_at timestamp:

Oban::Job.insert(worker: "MyWorker", args: {id: 1}, scheduled_at: 1.minute.from_now.utc)

Now, if you're using Rails 6+, you can also use insert_all to batch insert jobs:

Oban::Job.insert_all([
  {worker: "MyWorker", args: {id: 1}, queue: "default"},
  {worker: "MyWorker", args: {id: 2}, queue: "default"},
  {worker: "MyWorker", args: {id: 3}, queue: "default"},
])

Most columns in oban_jobs have sensible defaults, so only the worker and args are typically required. For integrity, all required columns are marked as NON NULL, and several have CHECK constraints as well for extra enforcement.

That's all you need to start migrating background jobs from Rails to Elixir (if you're using Oban, that is). Naturally, the same pattern would work for Python, Node, PHP, or any other language with a Postgres adapter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment