我正在构建一个消耗RabbitMQ消息的Elixir应用程序。使用amqp
库,我已经设置了gen_server
订阅Rabbit,并处理传入的消息。我想要的是,每个传入的消息都是异步处理的。这很简单 - 我可以抓住消息,将其粘贴在Task
中并将其关闭。更复杂的是, 希望{/ 1}}或ack
消息在任务之后处理它完成。为此,我需要监督任务(通过实际的nack
或仅Task.Supervisor
),然后等待Process.monitor
信号。
这里的事情对我来说有点混乱。我似乎找不到异步等待进程退出的方法。我要么必须使用EXIT
来捕获退出信号,要么运行Task.yield
消息循环(阻塞)。出路似乎是运行一个中间任务/主管来包装清理逻辑,但它看起来很难看。
所以,据我了解,我需要:
receive
是吗?如果没有,那是什么?
答案 0 :(得分:0)
如果您不习惯处理任务中的退出信息,最简单的方法是提供自己的帮助程序来包装任务以执行它,然后然后确认。它可能看起来像:
您的兔子中的 GenServer
def ack_me(channel, tag), do: Basic.ack(channel, tag)
包装
defmodule TaskAckHelper do
async_ack((() -> any), {binary(), bynary()}) :: Task.t
def async_ack(fun, {channel, tag}) do
Task.async(fn ->
fun.()
Rabbit.ack_me(channel, tag)
end)
end
async_ack({atom(), atom(), [any()]}, {binary(), bynary()}) :: Task.t
def async_ack({mod, fun, args} {channel, tag}) do
Task.async(fn ->
apply(mod, fun, args)
Rabbit.ack_me(channel, tag)
end)
end
end
现在在consume
你可能只是:
TaskAckHelper.async_ack(fn -> IO.puts(:ok) end, {channel, tag})
这个例子有点做作,在现实生活中你可能想要实现并产生一个Task.Supervisor
来编排从TaskAckHelper
创建的任务,但即使没有它也会按预期工作(尽管它是建议有一个主管来检查出口。)
答案 1 :(得分:0)
不建议在SO上推荐外部包装;我想将其作为评论发布,但是为了格式化而发布作为答案。
有一个用于增强Task.Supervisor
功能的程序包,称为Tarearbol
。它允许将任务结果的处理委托给第3方,指定回调和默认行为:
Tarearbol.ensure fn ->
result = PROCESS
{:ok, result}
end, accept_not_ok: false,
attempts: 3,
on_success: fn -> ACK end,
on_fail: fn -> NACK end
它将在内部处理崩溃,重试attempts
次并然后调用回调。