Closed cpursley closed 8 months ago
Are you thinking of these like phoenix router pipelines?
Yeah, kindof. I'm trying to get away from this sort of thing:
on_insert(:user, fn {:ok, user} ->
clear_cache(user)
send_email(user)
send_webhook(user)
# and possibly many more
end)
Well, I'm doing it like this actually:
on_insert(:user, fn {:ok, user} ->
~w(clear_cache send_email send_webhook)a
|> EventProcessor.process_event_async(appraisal)
end)
# I know, I know
defmodule EventProcessor do
defmacro process_event_async(functions, event) do
quote do
unquote(functions)
|> Enum.each(fn function ->
task_fn =
case function do
# If function is a tuple, treat it as {Module, function}
{mod, func} when is_atom(mod) and is_atom(func) ->
fn -> apply(mod, func, [unquote(event)]) end
# If function is an atom, treat it as a local function in the current module
func when is_atom(func) ->
fn -> apply(__MODULE__, func, [unquote(event)]) end
_ ->
raise ArgumentError, "Invalid function spec: #{inspect(function)}"
end
Task.start(task_fn)
end)
end
end
end
Yeah. I like the idea. You could even pass a context through all the functions similar to setups in ExUnit.
The function would take the event data as the arg. Functions could be applied asynchronously.
This is probably a bad idea for a variety of reasons, but might be cool.