Oban Training—Up and Running
Mix.install([:kino, :oban, :postgrex])
🏅 Goals
Through this exercise you’ll gain understanding of how to install Oban, prepare the database, and configure it to run in an application.
Installation
Typically, you’d install Oban into your application by adding the package to your deps
, adding some configuration, and generating a few migrations. Since this is LiveBook and not an application, we’ve already setup the :oban
package and we’ll skip straight to some simple configuration after some minimial setup.
Migrations
Oban requires a Postgres (or SQlite) and a functional Ecto.Repo
. For now, we’ll define a basic repo with minimal configuration:
Application.put_env(:myapp, MyApp.Repo, url: "postgres://localhost:5432/chow_mojo_dev")
defmodule MyApp.Repo do
use Ecto.Repo, adapter: Ecto.Adapters.Postgres, otp_app: :myapp
end
Now we’re ready to define a database migration that will create the various tables and indexes Oban requires to operate. Find the section on migrations in Oban’s installation guide and fill in up/0
and down/0
functions in the following migration:
use Oban.Migration
functions to define up
and down
:
def up do
Oban.Migration.up(version: 11)
end
def down do
Oban.Migration.down(version: 1)
end
defmodule MyApp.Repo.Migrations.AddOban do
use Ecto.Migration
# Your turn...
end
Without the convenience of running mix ecto.migrate
, we’ll handle creating the database and running migrations manually.
alias MyApp.Repo
Repo.__adapter__().storage_down(Repo.config())
Repo.__adapter__().storage_up(Repo.config())
MyApp.Repo.start_link()
Ecto.Migrator.run(Repo, [{0, MyApp.Repo.Migrations.AddOban}], :up, all: true)
Scroll through the migration output and note that there are tables, indexes, and other database entities created and destroyed. We’ll learn more about those tables and how they operate in future lessons. For now, let’s verify that everything can run properly.
Configuration
To verify everything is working we’ll start an Oban instance with the absolute minimum configuration, the repo
and a single default
queue.
Set start_opts
with a repo and queues:
start_opts: [repo: MyApp.Repo, queues: [default: 10]]
# Your turn...
start_opts = []
case Oban.start_link(start_opts) do
{:ok, pid} ->
pid
{:error, {:already_started, pid}} ->
pid
end
With a running Oban instance we have something to poke at. Start by seeing if the process is alive and fetching its configuration using Oban.config/0,1:
Oban.config()
The Oban.Config
struct has ample fields that we’ll ignore for now. The important thing is that the Oban instance is running and some config was found.
Now we’ll use Oban.check_queue/1 to verify that the default
queue you configured is alive as well:
Oban.check_queue(queue: :default)
# Your turn ...
The output from check_queue/1
shows diagnostics from the queue including how long it has been running, whether it is paused, the node it is running on, and which jobs its running. Note that the running
list is empty—because we haven’t created any workers or inserted any jobs!
Running Jobs
Running a “job” requires a worker module and a queue to pull it out of the database and execute it. We’ve already started a default
queue, which leaves the task of defining a worker module.
Any module that implements the Oban.Worker behaviour can be used as a job. Usually you’ll use Oban.Worker
to define a worker rather than implementing the behaviour directly.
Define a worker named MyApp.InspectWorker
that uses IO.inspect/1
to print the job
argument:
Define a perform/1
function that uses IO.inspect/2
:
@impl Oban.Worker
def perform(job) do
IO.inspect(job, label: "Running Job")
end
defmodule MyApp.InspectWorker do
use Oban.Worker
# Your turn...
end
Now we can use Oban.insert/1
to insert a job record into the database and let the default
queue execute it. When the job executes you’ll see the full details of the complete Oban.Job
struct.
Use MyApp.InspectWorker.new/1
to create a Job changeset and pass it into Oban.insert/1
:
%{some: :args}
|> MyApp.InspectWorker.new()
|> Oban.insert()
# Your turn...
There you have it—a minimual yet fully functional Oban installation 🎉!
From here on in we’re working on ChowMojo, a food delivery app for exotic pets. Throughout these exercises you’ll enhance the app’s functionality with one or more background processing tasks.
All foundational application setup, boilerplate modules, seed data, and other support is defined in the notebook’s setup.
☠️ Extra Challenges
Inspect migrated tables
Use psql
(Postgres console) or another database explorer tool to look at the tables, indexes, enums, and triggers created by Oban in the chow_mojo_dev
database.
-
How many
oban_
tables were created? - Which columns have indexes? Can you guess how they’re used?
Inspect the running Oban supervision tree
Look at which processes are running under the Oban
instance’s supervision tree either through beam tooling, the registry, or browsing the source code.
- What are the direct children of the Oban supervisor?
- Which process handles running queues?