问题
PROBLEM:
I have a function that gets triggered VIA Cronjob. This cronjob fires the function at 10:00pm but let's say the data required is not present for the function to properly be handled. I want to fail but then have the function retry an 1 hour. How would I handle this problem?
CODE:
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
So as you can see from this bit of code. If the query does not find the question I send the case statement to a failure but inside that fail case I want to return the function in 1 hour. How can I achieve this with Elixir/Phoenix? Thanks for the help!
回答1:
I prefer to enqueue tasks into a job system like Exq (redis backed) or ecto_job (postgresql backed) from the cron job.
From there it will automatically retry up to some maximum with a delay between retries.
It also has the benefit of surviving server reboots etc.
回答2:
The solution with GenServer
looks like an overkill to me here. I would go with a non-monitored task aka Task.start/1. The drawback of this solution is if task failed, nobody will get known about and the requested action won’t take an effect. If you must ensure, that the mission was completed successfully, use the solution provided by @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
And somewhere inside your cron-managed code:
Task.start @task
回答3:
You can use genserver to send msg to execute check_question
after 1 hour.
If the server shuts down, the timer will not keep counting down.
The timer will be automatically canceled if the given dest is a PID which is not alive or when the given PID exits.
In this case, self
returns the PID (process identifier) of the calling process.
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
来源:https://stackoverflow.com/questions/48362651/retry-function-on-failure-after-x-amount-of-time