elixir中的异步进程清理

时间:2017-11-29 00:31:59

标签: asynchronous elixir

我正在构建一个消耗RabbitMQ消息的Elixir应用程序。使用amqp库,我已经设置了gen_server订阅Rabbit,并处理传入的消息。我想要的是,每个传入的消息都是异步处理的。这很简单 - 我可以抓住消息,将其粘贴在Task中并将其关闭。更复杂的是, 希望{/ 1}}或ack消息任务之后处理它完成。为此,我需要监督任务(通过实际的nack或仅Task.Supervisor),然后等待Process.monitor信号。

这里的事情对我来说有点混乱。我似乎找不到异步等待进程退出的方法。我要么必须使用EXIT来捕获退出信号,要么运行Task.yield消息循环(阻塞)。出路似乎是运行一个中间任务/主管来包装清理逻辑,但它看起来很难看。

所以,据我了解,我需要:

receive

是吗?如果没有,那是什么?

2 个答案:

答案 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次并然后调用回调。