Packages
ash_oban
0.8.4
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0-rc.1
0.8.0-rc.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.1
0.5.0
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.6
0.2.5
0.2.4
0.2.3
0.2.3-rc.1
0.2.3-rc.0
0.2.2
0.2.1
0.2.0
0.1.14
0.1.13
0.1.12
0.1.11
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
The extension for integrating Ash resources with Oban.
Current section
Files
Jump to
Current section
Files
lib/transformers/define_action_workers.ex
# SPDX-FileCopyrightText: 2023 ash_oban contributors <https://github.com/ash-project/ash_oban/graphs/contributors>
#
# SPDX-License-Identifier: MIT
defmodule AshOban.Transformers.DefineActionWorkers do
# Define scheduler and worker modules.
@moduledoc false
use Spark.Dsl.Transformer
alias Spark.Dsl.Transformer
def after?(_), do: true
def transform(dsl) do
module = Transformer.get_persisted(dsl, :module)
dsl
|> AshOban.Info.oban_scheduled_actions()
|> Enum.reduce(dsl, fn scheduled_action, dsl ->
worker_module_name =
scheduled_action.worker_module_name || module_name(module, scheduled_action)
define_worker(module, worker_module_name, scheduled_action, dsl)
dsl
|> Transformer.replace_entity([:oban, :scheduled_actions], %{
scheduled_action
| worker: worker_module_name
})
end)
|> then(&{:ok, &1})
end
defp module_name(module, trigger) do
module
|> List.wrap()
|> Enum.concat(["AshOban", "ActionWorker"])
|> Enum.concat([Macro.camelize(to_string(trigger.name))])
|> Module.concat()
end
# sobelow_skip ["SQL.Query"]
defp define_worker(resource, worker_module_name, scheduled_action, dsl) do
domain = AshOban.Info.oban_domain!(dsl)
pro? = AshOban.Info.pro?()
function_name =
if pro? do
:process
else
:perform
end
worker =
if pro? do
Oban.Pro.Worker
else
Oban.Worker
end
Module.create(
worker_module_name,
quote location: :keep do
use unquote(worker),
priority: unquote(scheduled_action.priority),
max_attempts: unquote(scheduled_action.max_attempts),
queue: unquote(scheduled_action.queue),
tags: unquote(scheduled_action.tags || []),
unique: [
period: :infinity,
states: :incomplete
]
require Logger
@impl unquote(worker)
def unquote(function_name)(%Oban.Job{args: args} = job) do
scheduled_action =
AshOban.Info.oban_scheduled_action(unquote(resource), unquote(scheduled_action.name))
tenants =
(scheduled_action.list_tenants ||
AshOban.Info.oban_list_tenants!(unquote(resource)))
|> then(fn
{module, o} ->
module.list_tenants(o)
list_tenants ->
list_tenants
end)
if !Map.has_key?(args, "tenant") && Enum.count_until(tenants, 2) == 2 do
Enum.each(tenants, fn tenant ->
args
|> Map.put("tenant", tenant)
|> __MODULE__.new()
|> Oban.insert!()
end)
else
tenant =
if Map.has_key?(args, "tenant"), do: args["tenant"], else: List.first(tenants)
case AshOban.lookup_actor(args["actor"], unquote(scheduled_action.actor_persister)) do
{:ok, actor} ->
authorize? = AshOban.authorize?()
AshOban.debug(
"Scheduled action #{unquote(inspect(resource))}.#{unquote(scheduled_action.name)} triggered.",
unquote(scheduled_action.debug?)
)
input =
(args["action_arguments"] || %{})
|> Map.merge(unquote(Macro.escape(scheduled_action.action_input || %{})))
input =
if job.max_attempts == job.attempt do
Map.put(input, :last_oban_attempt?, true)
else
Map.put(input, :last_oban_attempt?, false)
end
unquote(resource)
|> Ash.ActionInput.new()
|> Ash.ActionInput.set_tenant(tenant)
|> Ash.ActionInput.set_context(
AshOban.build_context(
unquote(Macro.escape(scheduled_action.shared_context)),
job
)
)
|> Ash.ActionInput.for_action(
unquote(scheduled_action.action),
input,
authorize?: authorize?,
actor: actor,
domain: unquote(domain),
skip_unknown_inputs: Map.keys(input)
)
|> Ash.run_action!()
{:error, error} ->
raise Ash.Error.to_ash_error(error)
end
end
:ok
rescue
error ->
ash_error = Ash.Error.to_ash_error(error, __STACKTRACE__)
case AshOban.check_for_oban_return(ash_error) do
nil -> reraise error, __STACKTRACE__
result -> result
end
end
end,
Macro.Env.location(__ENV__)
)
end
end