如何在超时后杀死Elixir进程

时间:2016-01-17 11:42:00

标签: elixir

如何启动Elixir进程,然后在超时后将其终止?我有这样的代码:

defmodule OperationsManager do
  def run_operation do
    spawn fn -> 
      # long operation 
    end
  end
end

内部操作可能会持续太长时间才能结束,所以我需要从管理器中删除该进程。我该怎么办?

编辑:

重要细节:我需要生成几个操作,并且所有操作都应该有单独的超时。

3 个答案:

答案 0 :(得分:9)

为了完整性:erlang :timer模块有一个函数kill_after,它将在经过一段时间后强制终止进程。

# Kill the current process after 2 seconds 
:timer.kill_after(:timer.seconds(2))

# Kill pid after 2 minutes
:timer.kill_after(:timer.minutes(2), pid)

答案 1 :(得分:7)

我会看看Elixir Task module

您可以使用Task.yield或多个任务Task.yield_many处理单个任务,但Task.yield似乎更接近您可能需要的时间。 收益率返回{:ok, result}(成功返回),{:exit, reason}(任务崩溃)或:nil(超时间隔超时)。 您还可以考虑将任务放在监督树中。

以下代码基于elixir 1.2.1。

defmodule OperationsManager do
  def run_operation() do

    task1 = Task.async(fn() -> operation("task 1", 1) end)
    result = Task.yield(task1, 5000)
    process_task(task1, result)

    task2 = Task.async(fn() -> operation("task 2", 2) end)
    task4 = Task.async(fn() -> operation("task 4", 4) end)
    task6 = Task.async(fn() -> operation("task 6", 6) end)
    task8 = Task.async(fn() -> operation("task 8", 8) end)

    results = Task.yield_many([task2, task4, task6, task8], 7000)
    for {task, res} <- results do
      process_task(task, res)
    end

  end

  def process_task(task, res) do
    case res do
      :nil ->
        IO.write("shutting down timed out task: ")
        IO.inspect(task)
        Task.shutdown(task, :brutal_kill)
      {:ok, task_number} ->
        IO.puts("#{task_number} is complete")
      {:exit, _reason} ->
        # some logic when the task terminates
    end
  end

  def operation(task_number, timeout) do
    :timer.sleep(timeout * 1000)
    task_number
  end

end


OperationsManager.run_operation()

答案 2 :(得分:2)

您可以使用在进程之间发送消息来管理各种情况,例如:

parent_pid = self()
spawn_pid = spawn fn -> 
  # some code...
  # :timer.sleep(1_500)
  send(parent_pid, {:done, self()})
end
# wait a result from spawned proccess
receive do
  {:done, pid} -> "Got :done from #{inspect pid}"
after # 1s timeout
  1_000 -> Process.exit(spawn_pid, :kill)
end
# ensure that spawned process is finished or killed
Process.alive?(spawn_pid) # => false