Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Oban Training—Up and Running

01_up_and_running.livemd

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 a Hint

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.

Use a Hint

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:

Use a Hint
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:

Use a Hint

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 a Hint

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.

  1. How many oban_ tables were created?
  2. 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.

  1. What are the direct children of the Oban supervisor?
  2. Which process handles running queues?

Home

Signing Up