问题:
我有一个通过 Cronjob 触发的函数。此 cronjob 在晚上 10:00 触发函数,但假设不存在正确处理函数所需的数据。我想失败,但随后让函数重试 1 小时。我将如何处理此问题?
法典:
def check_question do
case question = Repo.get_by(Question, active: true, closed: true) do
question when not(is_nil(question)) ->
case ActiveQuestion.ready_for_answer_status(conn, question) do
end
_ ->
# RETRY CODE HERE
end
end
所以正如你从这段代码中看到的。如果查询找不到问题,我将 case 语句发送到失败,但在失败的情况下,我想在 1 小时内返回函数。我怎样才能用长生不老药/凤凰来实现这一点?感谢您的帮助!
GenServer
的解决方案对我来说似乎有点矫枉过正。我会选择一个不受监控的任务,也就是Task.start/1
.此解决方案的缺点是,如果任务失败,则没有人会知道,并且请求的操作不会生效。如果必须确保任务成功完成,请使用 @yonghao-hu 提供的解决方案。
@task fn ->
case question = Repo.get_by(Question, ...) do
question when not(is_nil(question)) ->
...
_ ->
Process.sleep(5_000) # delay
Task.start(@task)
end
end
在 cron 托管代码中的某个地方:
Task.start @task
您可以使用 genserver 发送消息以在 1 小时后执行check_question
。
如果服务器关闭,计时器将不会继续倒计时。
如果给定的目的地是PID,计时器将自动取消 它不是活动的,或者当给定的 PID 退出时。
在这种情况下,self
返回调用进程的 PID(进程标识符(。
defmodule Periodically do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, %{})
end
def init(state) do
# DingDing.Helper.update_all_company_users()
# One.Dingding.Auth.update_app_access_token()
check_question()
{:ok, state}
end
def handle_info(:update, state) do
check_question()
{:noreply, state}
end
def check_question do
case question = Repo.get_by(Question, active: true, closed: true) do
question when not(is_nil(question)) ->
case ActiveQuestion.ready_for_answer_status(conn, question) do
end
_ ->
Process.send_after(self(), :update, 60*60*1000)
end
end
end
我更喜欢将任务排队到像 exq(redis 支持(或 ecto_job(postgresql 支持(这样的作业系统中。
从那里,它将自动重试,直到某个最大值,并在重试之间有延迟。
它还具有在服务器重新启动等情况下幸存下来的好处。