请问我有问题,我正在用Elixir取代Predictive dialer。到目前为止,它已超出所有预期。但是,我正面临着一个问题。假设所有第三方依赖项都按预期工作,这段代码很有效,
def perform(phonebook_contacts, ...) do
alias FSModEvent.Connection, as: C
for x <-Enum.chunk(phonebook_contacts, 100, 100, []), y <- x do
unless Telephony.user_balance(account_number) <= 0 do
Task.start_link(fn ->
# some background job to dailout phone number y
end)
# :timer.sleep(1000);
end
...
end
phonebook_contacts
可以是包含多达200K数字的列表
我正在使用exq
。如果外部事件导致作业失败,当它被重试时,它从列表的开头开始,是否有一种方法可以从作业失败的最后一次联系重试?
假设[12,34,56,78,90…]
如果作业在56
处失败,它会再次从12
重新开始,有一种方法可以从78
(某种失败的地方)继续,......?或者更好的方法来处理这个用例
有建议可能将工作状态存储在redis中并从那里重试,但我不知道该怎么做。
答案 0 :(得分:1)
这里的简单方法是启动另一个流程,您可以使用该流程存储&#34;成功状态&#34;每个人的工作。然后,在任何类型的重新启动期间,您可以检查作业是否已经运行/完成。
Agent
是一个好的,易于使用的流程,用于跟踪您不需要执行更复杂交互的小部分状态。
例如:
def perform(phonebook_contacts, ...) do
completed_agent = Agent.new(fn -> MapSet.new() end)
# the Enum code...
Task.start_link(fn ->
completed? = Agent.get(completed_agent, &(MapSet.member?(&1, y)))
unless completed? do
# the dialout code...
if dialout_code_succeeded do
Agent.update(completed_agent, &MapSet.put(&1, y))
end
end
end)
end
现在,这可能是最天真的方式,并且可能不是特别高效。重要的是要注意Agent.get/3
和Agent.update/3
中提供的匿名功能有效地阻止来自任何其他进程的代理,因此您需要这些功能运行速度非常快,否则您可能会因尝试使用代理的其他进程造成超时。
答案 1 :(得分:0)
您可以使用起始索引作为参数创建递归作业。
如果作业失败,你可以拯救它并用当前索引加一个来自称。
在你的工作中你不再使用phonebook_contacts进行迭代,但是这个函数
defp enum_from(phonebook_contacts, index) do
Enum.slice(phonebook_contacts, index, Enum.count(phonebook_contacts))
end
当你第一次给你打电话时,你可以在索引0处调用它。
通过在
之后的索引处递归调用作业来捕获异常并跳过有问题的数字