Elixir任务 - 优雅关闭

时间:2015-08-12 23:41:24

标签: elixir task shutdown

我有Elixir Task,需要一些时间(10秒)。当应用程序升级时,尽管Task.Supervisor

,此任务仍被shutdown: 30000终止
=SUPERVISOR REPORT==== 13-Aug-2015::00:03:09 ===
 Supervisor: {local,tasks_sup}
 Context:    child_terminated
 Reason:     killed
 Offender:   [{pid,<0.304.0>},
              {id,'Elixir.Task.Supervised'},
              {mfargs,{'Elixir.Task.Supervised',start_link,undefined}},
              {restart_type,temporary},
              {shutdown,30000},
              {child_type,worker}]

我不知道如何在应用程序升级时优雅地停止任务(等到任务完成)。以下是描述我的问题的代码:

defmodule MyApp do
  use Application

  def start(_, _) do
    MyApp.Supervisor.start_link([])
  end

end

defmodule MyApp.Supervisor do

  use Supervisor

  def start_link(state) do
    Supervisor.start_link(__MODULE__, state, name: __MODULE__)
  end

  def init(state) do
    children = [
      supervisor(Task.Supervisor, [[name: :tasks_sup, shutdown: 30000]]),
      worker(MyApp.Worker, [state], restart: :permanent)
    ]

    supervise(children, strategy: :one_for_one)
  end

end

defmodule MyApp.Worker do

  def start_link(state) do
    GenServer.start_link(__MODULE__, state, [name: MyApp.Worker])
  end

  def init(state) do
    {:ok, state}
  end

  def handle_call(:which_children, _, state) do
    children = [{Task.Supervisor, :tasks_sup, :supervisor, [Task.Supervisor]}]
    {:reply, children, state}
  end

  def handle_info({:task, data}, state) do
    Task.Supervisor.async(:tasks_sup, MyApp.TaskRunner, :perform, [data])
  end

  def handle_info(_, state) do
    {:noreply, state}
  end

end

defmodule MyApp.TaskRunner do

  def perform(data) do
    # some 10 secs job
  end

end

是否有任何想法或假设如何等到MyApp.TaskRunner.perform完成然后允许停止任务?

对我来说如何处理任务并不重要:使用原生Elixir的Task或通过自己的一些TaskProcessor模块。

Task.Supervisor.async将任务链接到调用者,这可能是个问题。但是,我使用asyncstart_link尝试了几次不同的情况,每次都得到相同的结果。我的最新测试是:

children = [
  supervisor(Task.Supervisor, [[name: :tasks_sup, shutdown: 30000]]),
  worker(MyApp.Worker, [state], restart: :permanent)
]

supervise(children, strategy: :one_for_one)

Task.Supervisor.start_child(:tasks_sup, MyApp.TaskRunner, :perform, [data])

工人在大约2-3秒后被杀。

1 个答案:

答案 0 :(得分:1)

链接可能是将您的任务降低的链接。因为工作人员调用For Each tagsx In tags2 If tagsx.ID = "filterBtn" Then tagsx.Click Do Until Not IE.Busy DoEvents Loop End If Next tagsx ,所以它会将任务链接到您的工作人员。该工作程序的超时时间为5000毫秒,因此它将在主管之前关闭,从而终止任务。您可以通过设置之前的报告来确认。

顺便说一句,如果您稍后通过相同的流程致电Task.Supervisor.async,则应该只拨打async,而且此处似乎并非如此。您可能应该调用await(因此任务没有链接到调用者)。

您的函数被杀的另一个可能原因是VM只保留最新的两个代码模块版本。如果您在短时间间隔内升级两次,旧版本将被清除,其运行进程将被终止。