如何启动Elixir进程,然后在超时后将其终止?我有这样的代码:
defmodule OperationsManager do
def run_operation do
spawn fn ->
# long operation
end
end
end
内部操作可能会持续太长时间才能结束,所以我需要从管理器中删除该进程。我该怎么办?
编辑:
重要细节:我需要生成几个操作,并且所有操作都应该有单独的超时。
答案 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