-
-
Save ukchukx/d0bafea6469e779fcdd37060dc85b757 to your computer and use it in GitHub Desktop.
Elixir Task - Crash Handling
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This demonstrates that, when using async/await, a crash in the task will crash the caller | |
defmodule Tasker do | |
def good(message) do | |
IO.puts message | |
end | |
def bad(message) do | |
IO.puts message | |
raise "I'm BAD!" | |
end | |
end | |
IO.puts "Starting Async GOOD" | |
a = Task.async(Tasker, :good, ["-> Async GOOD"]) | |
IO.puts "Starting Async BAD" | |
b = Task.async(Tasker, :bad, ["-> Async BAD"]) | |
:timer.sleep 500 | |
IO.puts "Awaiting both" | |
Task.await(a) | |
Task.await(b) | |
# % elixir task1.exs | |
# Starting Async GOOD | |
# Starting Async BAD | |
# -> Async GOOD | |
# -> Async BAD | |
# ** (EXIT from #PID<0.47.0>) an exception was raised: | |
# ** (RuntimeError) I'm BAD! | |
# task1.exs:8: Tasker.bad/1 | |
# (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2 | |
# (elixir) lib/task/supervised.ex:40: Task.Supervised.reply/5 | |
# (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 | |
# | |
# 09:06:08.269 [error] Task #PID<0.54.0> started from #PID<0.47.0> terminating | |
# ** (RuntimeError) I'm BAD! | |
# task1.exs:8: Tasker.bad/1 | |
# (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2 | |
# (elixir) lib/task/supervised.ex:40: Task.Supervised.reply/5 | |
# (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 | |
# Function: &Tasker.bad/1 | |
# Args: ["-> Async BAD"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This demonstrates that, when using async/yield, a crash in the task will crash the caller. | |
# i.e. `async` always links the processes! Note that "I'm still alive" is not printed | |
defmodule Tasker do | |
def good(message) do | |
IO.puts message | |
end | |
def bad(message) do | |
IO.puts message | |
raise "I'm BAD!" | |
end | |
end | |
IO.puts "Starting Async GOOD" | |
a = Task.async(Tasker, :good, ["-> Async GOOD"]) | |
IO.puts "Starting Async BAD" | |
b = Task.async(Tasker, :bad, ["-> Async BAD"]) | |
:timer.sleep 500 | |
IO.puts "Awaiting both" | |
Task.yield(a) | |
Task.yield(b) | |
IO.puts "I'm still alive" | |
# % elixir task2.exs | |
# Starting Async GOOD | |
# Starting Async BAD | |
# -> Async GOOD | |
# -> Async BAD | |
# ** (EXIT from #PID<0.47.0>) an exception was raised: | |
# ** (RuntimeError) I'm BAD! | |
# task2.exs:9: Tasker.bad/1 | |
# (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2 | |
# (elixir) lib/task/supervised.ex:40: Task.Supervised.reply/5 | |
# (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 | |
# | |
# 09:08:23.912 [error] Task #PID<0.54.0> started from #PID<0.47.0> terminating | |
# ** (RuntimeError) I'm BAD! | |
# task2.exs:9: Tasker.bad/1 | |
# (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2 | |
# (elixir) lib/task/supervised.ex:40: Task.Supervised.reply/5 | |
# (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 | |
# Function: &Tasker.bad/1 | |
# Args: ["-> Async BAD"] | |
# |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This demonstrates that, when using start_link, the caller will not wait around | |
# on the task to finish - the caller will finish regardless of what happens in the | |
# task. | |
defmodule Tasker do | |
def good(message) do | |
:timer.sleep 500 | |
IO.puts message | |
end | |
def bad(message) do | |
:timer.sleep 500 | |
IO.puts message | |
raise "I'm BAD!" | |
IO.puts "After CRASH" | |
end | |
end | |
IO.puts "Starting start_link GOOD" | |
{:ok, pid1} = Task.start_link(Tasker, :good, ["-> Start Link GOOD"]) | |
IO.puts "Starting start_link BAD" | |
{:ok, pid2} = Task.start_link(Tasker, :bad, ["-> Start Link BAD"]) | |
IO.puts "PIDS:" | |
IO.inspect pid1 | |
IO.inspect pid2 | |
# There is no way to wait! | |
# % elixir task3.exs | |
# Starting start_link GOOD | |
# Starting start_link BAD | |
# PIDS: | |
# #PID<0.53.0> | |
# #PID<0.54.0> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This demonstrates that, when using start_link, the task can crash the caller | |
# if the caller is still running. | |
defmodule Tasker do | |
def good(message) do | |
IO.puts message | |
end | |
def bad(message) do | |
IO.puts message | |
raise "I'm BAD!" | |
IO.puts "After CRASH" | |
end | |
end | |
IO.puts "Starting start_link GOOD" | |
{:ok, pid1} = Task.start_link(Tasker, :good, ["-> Start Link GOOD"]) | |
IO.puts "Starting start_link BAD" | |
{:ok, pid2} = Task.start_link(Tasker, :bad, ["-> Start Link BAD"]) | |
:timer.sleep(1000) | |
IO.puts "PIDS:" | |
IO.inspect pid1 | |
IO.inspect pid2 | |
# % elixir task4.exs | |
# Starting start_link GOOD | |
# Starting start_link BAD | |
# -> Start Link GOOD | |
# -> Start Link BAD | |
# ** (EXIT from #PID<0.47.0>) an exception was raised: | |
# ** (RuntimeError) I'm BAD! | |
# task4.exs:10: Tasker.bad/1 | |
# (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2 | |
# (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 | |
# | |
# 09:19:30.200 [error] Task #PID<0.54.0> started from #PID<0.47.0> terminating | |
# ** (RuntimeError) I'm BAD! | |
# task4.exs:10: Tasker.bad/1 | |
# (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2 | |
# (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 | |
# Function: &Tasker.bad/1 | |
# Args: ["-> Start Link BAD"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This demonstrates that, when using start, the task does not crash the caller | |
# (but the exception status is printed to the screen) | |
defmodule Tasker do | |
def good(message) do | |
IO.puts message | |
end | |
def bad(message) do | |
IO.puts message | |
raise "I'm BAD!" | |
IO.puts "After CRASH" | |
end | |
end | |
IO.puts "Starting start GOOD" | |
{:ok, pid1} = Task.start(Tasker, :good, ["-> Start GOOD"]) | |
IO.puts "Starting start BAD" | |
{:ok, pid2} = Task.start(Tasker, :bad, ["-> Start BAD"]) | |
:timer.sleep(1000) | |
IO.puts "PIDS:" | |
IO.inspect pid1 | |
IO.inspect pid2 | |
# % elixir task5.exs | |
# Starting start GOOD | |
# Starting start BAD | |
# -> Start GOOD | |
# -> Start BAD | |
# | |
# 09:21:51.944 [error] Task #PID<0.54.0> started from #PID<0.47.0> terminating | |
# ** (RuntimeError) I'm BAD! | |
# task5.exs:9: Tasker.bad/1 | |
# (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2 | |
# (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 | |
# Function: &Tasker.bad/1 | |
# Args: ["-> Start BAD"] | |
# PIDS: | |
# #PID<0.53.0> | |
# #PID<0.54.0> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This demonstrates that, when using start, the task does not crash the caller, | |
# but the tasks do not live past the life of the caller. I've switched from | |
# `IO.puts` in the tasks to `File.write` to show that the side-effect never | |
# happens. | |
defmodule Tasker do | |
def good(message) do | |
:timer.sleep(1000) | |
File.write("./task_good.txt", "#{message} - #{inspect(make_ref)}") | |
end | |
def bad(message) do | |
:timer.sleep(1000) | |
File.write("./task_bad.txt", "#{message} - #{inspect(make_ref)}") | |
raise "I'm BAD!" | |
end | |
end | |
IO.puts "Starting start GOOD" | |
{:ok, pid1} = Task.start(Tasker, :good, ["-> Start GOOD"]) | |
IO.puts "Starting start BAD" | |
{:ok, pid2} = Task.start(Tasker, :bad, ["-> Start BAD"]) | |
IO.puts "PIDS:" | |
IO.inspect pid1 | |
IO.inspect pid2 | |
# % elixir task6.exs | |
# Starting start GOOD | |
# Starting start BAD | |
# PIDS: | |
# #PID<0.53.0> | |
# #PID<0.54.0> | |
# % ls task_*.txt | |
# ls: task_*.txt: No such file or directory |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This demonstrates that, when using async_nolink, the task only crashes | |
# the caller when we call await. Note that "I'm still alive" is not | |
# printed | |
defmodule Tasker do | |
def good(message) do | |
:timer.sleep(1000) | |
IO.puts message | |
end | |
def bad(message) do | |
:timer.sleep(1000) | |
IO.puts message | |
raise "I'm BAD!" | |
end | |
end | |
{:ok, pid} = Task.Supervisor.start_link() | |
IO.puts "Starting async_nolink GOOD" | |
a = Task.Supervisor.async_nolink(pid, Tasker, :good, ["-> Start GOOD"]) | |
IO.puts "Starting async_nolink BAD" | |
b = Task.Supervisor.async_nolink(pid, Tasker, :bad, ["-> Start BAD"]) | |
IO.puts "Awaiting both" | |
Task.await(a) | |
Task.await(b) | |
IO.puts "I'm still alive" | |
# % elixir task7.exs | |
# Starting async_nolink GOOD | |
# Starting async_nolink BAD | |
# Awaiting both | |
# -> Start GOOD | |
# -> Start BAD | |
# | |
# 09:55:05.130 [error] Task #PID<0.55.0> started from #PID<0.47.0> terminating | |
# ** (RuntimeError) I'm BAD! | |
# task7.exs:13: Tasker.bad/1 | |
# (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2 | |
# (elixir) lib/task/supervised.ex:40: Task.Supervised.reply/5 | |
# (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 | |
# Function: &Tasker.bad/1 | |
# Args: ["-> Start BAD"] | |
# ** (exit) exited in: Task.await(%Task{owner: #PID<0.47.0>, pid: #PID<0.55.0>, ref: #Reference<0.0.1.14>}, 5000) | |
# ** (EXIT) an exception was raised: | |
# ** (RuntimeError) I'm BAD! | |
# task7.exs:13: Tasker.bad/1 | |
# (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2 | |
# (elixir) lib/task/supervised.ex:40: Task.Supervised.reply/5 | |
# (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 | |
# (elixir) lib/task.ex:332: Task.await/2 | |
# task7.exs:28: (file) | |
# (elixir) lib/code.ex:363: Code.require_file/2 | |
# | |
# | |
# 09:55:05.157 [error] GenServer #PID<0.53.0> terminating | |
# ** (stop) exited in: Task.await(%Task{owner: #PID<0.47.0>, pid: #PID<0.55.0>, ref: #Reference<0.0.1.14>}, 5000) | |
# ** (EXIT) an exception was raised: | |
# ** (RuntimeError) I'm BAD! | |
# task7.exs:13: Tasker.bad/1 | |
# (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2 | |
# (elixir) lib/task/supervised.ex:40: Task.Supervised.reply/5 | |
# (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 | |
# Last message: {:EXIT, #PID<0.47.0>, {{%RuntimeError{message: "I'm BAD!"}, [{Tasker, :bad, 1, [file: 'task7.exs', line: 13]}, {Task.Supervised, :do_apply, 2, [file: 'lib/task/supervised.ex', line: 89]}, {Task.Supervised, :reply, 5, [file: 'lib/task/supervised.ex', line: 40]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 240]}]}, {Task, :await, [%Task{owner: #PID<0.47.0>, pid: #PID<0.55.0>, ref: #Reference<0.0.1.14>}, 5000]}}} | |
# State: {:state, {#PID<0.53.0>, Supervisor.Default}, :simple_one_for_one, [{:child, :undefined, Task.Supervised, {Task.Supervised, :start_link, []}, :temporary, 5000, :worker, [Task.Supervised]}], {:set, 0, 16, 16, 8, 80, 48, {[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []}, {{[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []}}}, 3, 5, [], Supervisor.Default, {:ok, {{:simple_one_for_one, 3, 5}, [{Task.Supervised, {Task.Supervised, :start_link, []}, :temporary, 5000, :worker, [Task.Supervised]}]}}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This demonstrates that, when using async_nolink, the task does not crash | |
# if we use `yield` to capture results | |
# Note that "I'm still alive" IS printed, and we get results from the tasks | |
defmodule Tasker do | |
def good(message) do | |
:timer.sleep(1000) | |
IO.puts message | |
end | |
def bad(message) do | |
:timer.sleep(1000) | |
IO.puts message | |
raise "I'm BAD!" | |
end | |
end | |
{:ok, pid} = Task.Supervisor.start_link() | |
IO.puts "Starting async_nolink GOOD" | |
a = Task.Supervisor.async_nolink(pid, Tasker, :good, ["-> Start GOOD"]) | |
IO.puts "Starting async_nolink BAD" | |
b = Task.Supervisor.async_nolink(pid, Tasker, :bad, ["-> Start BAD"]) | |
IO.puts "Awaiting both" | |
res_a = Task.yield(a) | |
res_b = Task.yield(b) | |
IO.puts "I'm still alive" | |
IO.puts "Result A: #{inspect(res_a)}" | |
IO.puts "Result B: #{inspect(res_b)}" | |
# % elixir task8.exs | |
# Starting async_nolink GOOD | |
# Starting async_nolink BAD | |
# Awaiting both | |
# -> Start GOOD | |
# -> Start BAD | |
# I'm still alive | |
# Result A: {:ok, :ok} | |
# | |
# 09:57:48.659 [error] Task #PID<0.55.0> started from #PID<0.47.0> terminating | |
# ** (RuntimeError) I'm BAD! | |
# task8.exs:13: Tasker.bad/1 | |
# (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2 | |
# (elixir) lib/task/supervised.ex:40: Task.Supervised.reply/5 | |
# (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 | |
# Function: &Tasker.bad/1 | |
# Args: ["-> Start BAD"] | |
# Result B: {:exit, {%RuntimeError{message: "I'm BAD!"}, [{Tasker, :bad, 1, [file: 'task8.exs', line: 13]}, {Task.Supervised, :do_apply, 2, [file: 'lib/task/supervised.ex', line: 89]}, {Task.Supervised, :reply, 5, [file: 'lib/task/supervised.ex', line: 40]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 240]}]}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment