Packages
Event-driven notification system for Ash Framework with multiple transport types
Current section
Files
Jump to
Current section
Files
lib/changes/enqueue_retry_job.ex
defmodule AshDispatch.Changes.EnqueueRetryJob do
@moduledoc """
Enqueues a new Oban job when a delivery receipt is retried.
This change ensures that when a user manually retries a failed delivery,
a new Oban job is created to process it.
"""
use Ash.Resource.Change
alias AshDispatch.Workers.SendEmail
require Logger
@impl true
def change(changeset, _opts, _context) do
Ash.Changeset.after_action(changeset, fn _changeset, receipt ->
case enqueue_job(receipt) do
{:ok, %{id: job_id}} when is_integer(job_id) ->
Logger.info("EnqueueRetryJob: Created Oban job #{job_id} for receipt #{receipt.id}")
# Persist the new job ID to the database
receipt
|> Ash.Changeset.for_update(:update, %{oban_job_id: job_id}, authorize?: false)
|> Ash.update(authorize?: false)
{:ok, _direct} ->
# Direct retry (e.g. in_app) — no Oban job created
Logger.info("EnqueueRetryJob: Direct retry for receipt #{receipt.id}")
{:ok, receipt}
{:error, reason} ->
Logger.error(
"EnqueueRetryJob: Failed to enqueue job for receipt #{receipt.id}: #{inspect(reason)}"
)
# Still return ok - the receipt was updated, job just failed
{:ok, receipt}
end
end)
end
defp enqueue_job(%{transport: :email} = receipt) do
%{receipt_id: receipt.id}
|> SendEmail.new()
|> Oban.insert()
end
defp enqueue_job(%{transport: :in_app} = receipt) do
# In-app delivery is synchronous — retry directly
case AshDispatch.Transports.InApp.retry_from_receipt(receipt) do
:ok -> {:ok, %{id: :direct_retry}}
error -> error
end
end
defp enqueue_job(%{transport: transport} = receipt) do
Logger.warning(
"EnqueueRetryJob: Retry not implemented for transport #{transport}, receipt_id=#{receipt.id}"
)
{:error, :transport_not_supported}
end
end