Retry function on failure after x amount of time

折月煮酒 提交于 2019-12-11 06:02:46

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!