Configurando quantidade de tentativas no Oban

Mesmo com o mecanismo de retry do Tesla, nossa requisição pode falhar e o Tesla não conseguir se recuperar. Para termos mais chance de sucesso, podemos configurar a quantidade de tentativas que o Oban poderá fazer antes de desistir. Por padrão ele tenta uma vez, mas podemos aumentar a quantidade. Nesse exemplo colocarei duas tentativas.

Para configurar, vamos adicionar opções a nossa Oban.Worker:

lib/coffee_shop/integrations/coffee/hot_coffees_worker.ex
defmodule CoffeeShop.Integrations.Coffee.HotCoffeesWorker do
  use Oban.Worker, max_attempts: 2

  alias CoffeeShop.Integrations.Coffee.Response
  alias CoffeeShop.Integrations.Coffee.Client

  @impl Oban.Worker
  def perform(%Oban.Job{args: %{"opts" => opts}}) do
    opts = to_list(opts)
    
    case Client.all_hot_coffees(opts) do
      {:ok, %Response{status: 200, body: _body}} -> :ok
      {:ok, %Response{status: status, body: _body}} -> {:error, "status: #{status}"}
      error -> error
    end
  end

  defp to_list(map) do
    Enum.map(map, fn {key, value} -> {String.to_existing_atom(key), value} end)
  end
end

Adicionamos a opção max_attempts para 2 . Agora precisamos testar se a configuração está correta.

test/coffee_shop/integrations/coffee/client_test.exs
defmodule CoffeeShop.Integrations.Coffee.ClientTest do

  # ...
  
  describe "all_hot_coffees_async/0" do
    test "schedule and execute a job", %{bypass: bypass} do
      Bypass.expect_once(bypass, "GET", "/coffee/hot", fn conn ->
        Plug.Conn.resp(conn, 200, "")
      end)

      opts = [
        base_url: "http://localhost:3000",
        retry_delay: 1
      ]

      in_a_day = DateTime.add(DateTime.utc_now(), 3600 * 24, :second)

      assert {:ok, job} = Client.all_hot_coffees_async(opts)
      assert job.max_attempts == 2

      assert_enqueued(
        worker: HotCoffeesWorker,
        args: %{"base_url" => "http://localhost:3000", "retry_delay" => 1},
        scheduled_at: in_a_day
      )

      args = %{opts: Map.new(opts, fn option -> option end)}

      assert :ok = perform_job(HotCoffeesWorker, args)
    end
  end
end

Na linha 19 fazemos um check se o máximo de tentativas reflete o configurado. Deixamos o resto com o Oban.

Atualizado