Elixir 长时间运行的后台任务未完成,有时会崩溃

Posted

技术标签:

【中文标题】Elixir 长时间运行的后台任务未完成,有时会崩溃【英文标题】:Elixir long running background task doesn't complete, sometimes crashes 【发布时间】:2018-09-06 14:12:53 【问题描述】:

作为一点背景知识,我有一个负责视频上传的端点。我想要做的是将视频文件从请求复制到一个临时位置,并启动一个异步任务(ffmpeg shell 进程)以在后台对该视频进行转码,以便我的端点可以及时返回 200,并且响应不会等待 ffmpeg 完成对该视频的转码。

这是我的控制器代码。

def create(conn, %"file" => file ... )
    uuid = Video.uuid()
    tmp_path = Application.get_env(:myapp, :video_tmp_path) <> "/" <> uuid
    :ok = File.cp(file.path, tmp_path)
    VideoService.process(tmp_path, final_path)

VideoService 内部如下所示。

defmodule MyApp.Services do
  defmodule VideoService do
    def process(tmp_path, final_path) do
      Task.start_link fn ->
        System.cmd("ffmpeg", ["-i", tmp_path, final_path, "-hide_banner"])
        File.rm(tmp_path)
      end
    end
  end
end

我在这里遇到的问题是,无论如何,System.cmd("ffmpeg") 调用之后的任何内容都不会在VideoService 中执行,有时System.cmd 调用甚至不会启动ffmpeg 进程。我在这里做错了吗?我需要的是一种在后台从控制器/服务中旋转这个ffmpeg shell 进程并在视频上传时响应 200 的方法。提前感谢您的帮助。我是elixir / OTP的新手,所以我确定我在做一些愚蠢的事情。

我也随机看到如下错误

erl_child_setup: failed with error 32 on line 240

【问题讨论】:

旁注:当服务器接受请求,但处理尚未完成时,服务器必须响应202 Accepted而不是200 OK. 首先将结果从System.cmd/2 吐出到日志中以供进一步调查:IO.inspect(System.cmd(...))。另一个问题是:你检查过你的凤凰日志吗?它是否包含任何相关内容? 我不确定你从哪里调用这个process,但请注意Task.start_link/1 链接到父进程并且一旦父进程死亡,它也死了。可能的解决方案是在您的监督树中拥有一个专用的GenServer,它将产生任务。这样您就可以确保父进程始终处于活动状态。 尝试在应用的主管中启动Task.Supervisor 的实例,然后使用Task.Supervisor.start_child 启动任务。这应该可以解决@mudasobwa 指出的问题。 我会试一试,让你们俩都知道会发生什么。感谢您的建议和指导! 【参考方案1】:

感谢 mudasobwa 和 Dogbert 帮助回答这个问题。我跟着this guide 让一个独立的主管按照他们的建议在我的凤凰堆栈中启动并运行。这样做的要点是在lib/myapp.ex 中添加一行来创建这样的主管

supervisor(Task.Supervisor, [[name: MyApp.TaskSupervisor]])

然后当你想以那个supervisor为父运行任务时,你可以运行

Task.Supervisor.start_child(MyApp.TaskSupervisor, fn -&gt; do_stuff() end)

就我而言,do_stuff 涉及生成一个 ffmpeg 进程并进行一些文件清理。这里的基本思想是,您将主管作为父级进行这项工作,这样即使请求退出并且该进程终止,您的主管仍然活着并且很好,因为当您的应用程序启动时它始终处于启动状态。

【讨论】:

以上是关于Elixir 长时间运行的后台任务未完成,有时会崩溃的主要内容,如果未能解决你的问题,请参考以下文章

在后台运行长时间运行的并行任务,同时允许小型异步任务更新前台

运行后台任务时防止 IIS 空闲超时

保持程序在后台长时间运行-b

在 Rails 中运行大量长时间运行的后台作业

关于ios中后台长时间下载任务的实现与走过的坑

带有进度通知的长时间运行的后台任务