Oban function has no local return and jobs stuck in 'available'

Around the time I’ve moved to elixir 1.11.2 and otp23 after Oban.insert() my Oban perform() function does not fire and Dialyzer complains that perform() has no local return.

I call a function Emails.welcome_email() that sends an email via Bamboo and returns :ok(Dialyzer also complains that Emails.welcome_email() has no local return )

Up until now I’ve had no issue, and it’s not clear to me what has happened. code execution ends after new() in the Oban job build() call and even simply returning :ok in the perform() function seems to not short-circuit the Dialyzer error.

I’m using elixir 1.11.2, otp23.1.2, oban 2.1, bamboo 1.5 and postgres 13.0

my config.exs:

config :markably, Oban,
  repo: Markably.Repo,
  plugins: [Oban.Plugins.Pruner],
  queues: [default: 10, mailers: 20, events: 50, media: 5]

application.ex:

defmodule Markably.Accounts.Jobs.WelcomeEmail do
  alias Markably.Emails
  use Oban.Worker, queue: :mailers, max_attempts: 4

  def build(email, org_name, url), do: new(%{email: email, org_name: org_name, url: url})

  def perform(%Oban.Job{args: %{"email" => email, "org_name" => org_name, "url" => url}}) do
    Emails.welcome_email(%{email: email, org_name: org_name, url: url})
  end
end
  def welcome_email(%{email: email, org_name: org_name, url: url}) do
    base_email()
    |> subject("#{org_name} - Welcome!")
    |> to(email)
    |> assign(:email, email)
    |> assign(:org_name, org_name)
    |> assign(:url, url)
    |> render_i18n(:welcome_email)
    |> premail()
    |> Markably.Mailer.deliver_now()

    :ok
  end

The dialyzer error is a red herring here; it is definitely down to some error in the welcome_email pipe chain, but it isn’t effecting whether the job is stuck available. My guess is that you’re testing this locally using something like iex -S mix phx.server, in which case the IEx.started? call in your application startup is preventing it from running.

To verify, replace this block in your application.ex with just opts:

if Code.ensure_loaded?(IEx) and IEx.started?() do
  opts
  |> Keyword.put(:crontab, false)
  |> Keyword.put(:queues, false)
else
  opts
end
1 Like

That was it, thanks. Verified your root cause analysis by returning opts.

This was driving me crazy; there was a point where mail delivery was working locally on my dev machine but not on the deployment. Thanks again!

1 Like