You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Elixir/Phoenix中实现失败后1小时重试定时触发函数

嘿,这个场景我太熟悉了!在Elixir/Phoenix里实现这种延迟重试,有两种靠谱的路子,我给你拆解下最适合生产和快速实现的方案:

方案一:用Oban实现持久化延迟重试(生产环境首选)

Oban是Elixir生态里专门处理后台任务、重试、调度的工具,自带数据库持久化——就算服务器重启,重试任务也不会丢,完美适配这种需要可靠重试的定时任务场景。

具体步骤:

  1. 先确保项目已经集成Oban(没装的话,先在mix.exs里加依赖并配置好数据库连接)
  2. 把你的check_question逻辑包装成Oban Worker:
defmodule MyApp.RetryQuestionCheckWorker do
  use Oban.Worker, queue: :default, max_attempts: 5 # 可自定义最大重试次数,避免无限循环

  @impl Oban.Worker
  def perform(_args) do
    case Repo.get_by(Question, active: true, closed: true) do
      %Question{} = question ->
        # 执行你的核心处理逻辑
        case ActiveQuestion.ready_for_answer_status(conn, question) do
          # 这里写正常处理分支的代码
        end
      nil ->
        # 手动调度1小时后的重试任务(3600秒=1小时)
        %__MODULE__{}
        |> Oban.insert(schedule_in: 3600)
        {:ok, "已调度1小时后重试"}
    end
  end
end
  1. 修改你的Cron配置,让它触发这个Worker而非直接调用函数:
    比如在config/schedule.ex的Quantum调度器里:
defmodule MyApp.Scheduler do
  use Quantum.Scheduler, otp_app: :my_app

  job "nightly_question_check",
    schedule: "0 22 * * *", # 每晚10点执行
    task: fn ->
      MyApp.RetryQuestionCheckWorker.new(%{}) |> Oban.insert()
    end
end

这样一来,第一次执行找不到符合条件的Question时,Oban会自动把重试任务存在数据库里,到点自动触发,完全不用担心任务丢失。

方案二:用Process.send_after实现轻量延迟(适合简单场景)

如果不想引入第三方库,也可以用Elixir原生的Process.send_after实现,但要注意:这种方式没有持久化,如果承载任务的进程挂了,重试任务就会丢失,更适合开发环境或对可靠性要求不高的场景。

修改你的check_question函数:

def check_question do
  case Repo.get_by(Question, active: true, closed: true) do
    %Question{} = question ->
      case ActiveQuestion.ready_for_answer_status(conn, question) do
        # 正常处理逻辑
      end
    nil ->
      # 1小时后给当前进程发消息触发重试(单位是毫秒)
      Process.send_after(self(), :retry_check_question, 3600 * 1000)
      :ok
  end
end

# 还要在承载这个函数的进程(比如GenServer或任务进程)里处理重试消息:
def handle_info(:retry_check_question, state) do
  check_question()
  {:noreply, state}
end

注意:这种方式要求承载任务的进程必须持续存活,否则重试消息会直接丢失。如果是Cron触发的一次性任务,建议把逻辑放在一个持久运行的GenServer里,或者用Task.Supervisor来管理任务生命周期。

额外提醒
  • 不管用哪种方案,都要设置最大重试次数,比如Oban的max_attempts,避免无限重试浪费资源
  • 确保你的数据库查询和业务逻辑是幂等的——多次执行不会产生重复或错误的副作用
  • 如果ActiveQuestion.ready_for_answer_status里也可能因为数据未就绪失败,记得把这部分也加入重试逻辑里

内容的提问来源于stack exchange,提问作者Bitwise

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:40:40