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

时间:2018-03-28 02:44:00

标签: ffmpeg erlang elixir phoenix-framework otp

作为一点背景,我有一个负责视频上传的端点。我想要做的是将视频文件复制到请求的临时位置,并启动异步任务(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调用甚至不会启动{ {1}}进程。我在这里做错了吗?我需要的是一种从控制器/服务在后台旋转此ffmpeg shell进程的方法,并在视频上传时响应200。提前感谢您的帮助。我是elixir / OTP的新手,所以我确定我做的事情很愚蠢。

我也随机看到以下错误

ffmpeg

1 个答案:

答案 0 :(得分:2)

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

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

然后,当您想要以该主管作为父项运行任务时,您可以运行

Task.Supervisor.start_child(MyApp.TaskSupervisor, fn -> do_stuff() end)

就我而言,do_stuff涉及产生ffmpeg进程并进行一些文件清理。这里的基本想法是,你正在以Supervisor作为父母进行这项工作,这样即使请求退出并且该过程终止,你的主管仍然活着并且很好,因为当你的应用程序启动时它总是在运行。