Skip to content

Commit d54d0f6

Browse files
author
José Valim
committed
Log when tasks go down
1 parent 72d2f38 commit d54d0f6

File tree

8 files changed

+97
-23
lines changed

8 files changed

+97
-23
lines changed

lib/elixir/lib/agent/server.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ defmodule Agent.Server do
4444
# There is a race condition if the agent is
4545
# restarted too fast and it is registered.
4646
try do
47-
self |> Process.info(:registered_name) |> elem(1) |> Process.unregister
47+
self |> :erlang.process_info(:registered_name) |> elem(1) |> Process.unregister
4848
rescue
4949
_ -> :ok
5050
end

lib/elixir/lib/process.ex

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,18 @@ defmodule Process do
368368
369369
See http://www.erlang.org/doc/man/erlang.html#process_info-2 for more info.
370370
"""
371-
@spec info(pid, atom) :: {atom, term}
372-
def info(pid, spec) do
371+
@spec info(pid, atom) :: {atom, term} | nil
372+
def info(pid, spec)
373+
374+
def info(pid, :registered_name) do
375+
case :erlang.process_info(pid, :registered_name) do
376+
:undefined -> nil
377+
[] -> {:registered_name, nil}
378+
other -> other
379+
end
380+
end
381+
382+
def info(pid, spec) when is_atom(spec) do
373383
nillify :erlang.process_info(pid, spec)
374384
end
375385

lib/elixir/lib/task.ex

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ defmodule Task do
106106
"""
107107
@spec start_link(module, atom, [term]) :: {:ok, pid}
108108
def start_link(mod, fun, args) do
109-
Task.Supervised.start_link({mod, fun, args})
109+
Task.Supervised.start_link(get_info(self), {mod, fun, args})
110110
end
111111

112112
@doc """
@@ -135,12 +135,17 @@ defmodule Task do
135135
@spec async(module, atom, [term]) :: t
136136
def async(mod, fun, args) do
137137
mfa = {mod, fun, args}
138-
pid = :proc_lib.spawn_link(Task.Supervised, :async, [self(), mfa])
138+
pid = :proc_lib.spawn_link(Task.Supervised, :async, [self, get_info(self), mfa])
139139
ref = Process.monitor(pid)
140140
send(pid, {self(), ref})
141141
%Task{pid: pid, ref: ref}
142142
end
143143

144+
defp get_info(self) do
145+
{node(),
146+
self |> Process.info(:registered_name) |> elem(1) |> Kernel.||(self)}
147+
end
148+
144149
@doc """
145150
Awaits for a task reply.
146151

lib/elixir/lib/task/supervised.ex

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
defmodule Task.Supervised do
22
@moduledoc false
33

4-
def start_link(fun) do
5-
{:ok, :proc_lib.spawn_link(__MODULE__, :noreply, [fun])}
4+
def start_link(info, fun) do
5+
{:ok, :proc_lib.spawn_link(__MODULE__, :noreply, [info, fun])}
66
end
77

8-
def start_link(caller, fun) do
9-
:proc_lib.start_link(__MODULE__, :reply, [caller, fun])
8+
def start_link(caller, info, fun) do
9+
:proc_lib.start_link(__MODULE__, :reply, [caller, info, fun])
1010
end
1111

12-
def async(caller, mfa) do
12+
def async(caller, info, mfa) do
1313
ref = receive do: ({^caller, ref} -> ref)
14-
send caller, {ref, apply(mfa)}
14+
send caller, {ref, do_apply(info, mfa)}
1515
end
1616

17-
def reply(caller, mfa) do
17+
def reply(caller, info, mfa) do
1818
:erlang.link(caller)
1919
:proc_lib.init_ack({:ok, self()})
2020

@@ -41,21 +41,47 @@ defmodule Task.Supervised do
4141
5000 -> exit(:timeout)
4242
end
4343

44-
send caller, {ref, apply(mfa)}
44+
send caller, {ref, do_apply(info, mfa)}
4545
end
4646

47-
def noreply(mfa) do
48-
apply(mfa)
47+
def noreply(info, mfa) do
48+
do_apply(info, mfa)
4949
end
5050

51-
def apply({module, fun, args}) do
51+
defp do_apply(info, {module, fun, args} = mfa) do
5252
try do
5353
apply(module, fun, args)
5454
catch
55-
:error, reason ->
56-
exit({reason, System.stacktrace()})
55+
:error, value ->
56+
exit(info, mfa, {value, System.stacktrace()})
5757
:throw, value ->
58-
exit({{:nocatch, value}, System.stacktrace()})
58+
exit(info, mfa, {{:nocatch, value}, System.stacktrace()})
59+
:exit, value ->
60+
exit(info, mfa, value)
5961
end
6062
end
63+
64+
defp exit(_info, _mfa, reason)
65+
when reason == :normal
66+
when reason == :shutdown
67+
when tuple_size(reason) == 2 and elem(reason, 0) == :shutdown do
68+
exit(reason)
69+
end
70+
71+
defp exit(info, mfa, reason) do
72+
:error_logger.format(
73+
"** Task ~p terminating~n" <>
74+
"** Started from ~p~n" <>
75+
"** Running ~p~n" <>
76+
"** Reason for termination == ~n" <>
77+
"** ~p~n", [self, get_from(info), get_running(mfa), reason])
78+
79+
exit(reason)
80+
end
81+
82+
defp get_from({node, pid_or_name}) when node == node(), do: pid_or_name
83+
defp get_from(other), do: other
84+
85+
defp get_running({:erlang, :apply, [fun, []]}), do: fun
86+
defp get_running(other), do: other
6187
end

lib/elixir/lib/task/supervisor.ex

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ defmodule Task.Supervisor do
5555
"""
5656
@spec async(Supervisor.supervisor, module, atom, [term]) :: Task.t
5757
def async(supervisor, module, fun, args) do
58-
{:ok, pid} = Supervisor.start_child(supervisor, [self(), {module, fun, args}])
58+
args = [self, get_info(self), {module, fun, args}]
59+
{:ok, pid} = Supervisor.start_child(supervisor, args)
5960
ref = Process.monitor(pid)
6061
send pid, {self(), ref}
6162
%Task{pid: pid, ref: ref}
@@ -98,6 +99,11 @@ defmodule Task.Supervisor do
9899
"""
99100
@spec start_child(Supervisor.supervisor, module, atom, [term]) :: {:ok, pid}
100101
def start_child(supervisor, module, fun, args) do
101-
Supervisor.start_child(supervisor, [{module, fun, args}])
102+
Supervisor.start_child(supervisor, [get_info(self), {module, fun, args}])
103+
end
104+
105+
defp get_info(self) do
106+
{node(),
107+
self |> Process.info(:registered_name) |> elem(1) |> Kernel.||(self)}
102108
end
103109
end

lib/elixir/test/elixir/process_test.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,26 @@ defmodule ProcessTest do
1414
quote(do: :erlang.monitor(:process, pid()))
1515
end
1616

17+
test "info/2" do
18+
pid = spawn fn -> end
19+
Process.exit(pid, :kill)
20+
assert Process.info(pid, :backtrace) == nil
21+
end
22+
23+
test "info/2 with registered name" do
24+
pid = spawn fn -> end
25+
Process.exit(pid, :kill)
26+
assert Process.info(pid, :registered_name) ==
27+
nil
28+
29+
assert Process.info(self, :registered_name) ==
30+
{:registered_name, nil}
31+
32+
Process.register(self, __MODULE__)
33+
assert Process.info(self, :registered_name) ==
34+
{:registered_name, __MODULE__}
35+
end
36+
1737
defp expand(expr, env) do
1838
{expr, _env} = :elixir_exp.expand(expr, env)
1939
expr

lib/elixir/test/elixir/task/supervisor_test.exs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ defmodule Task.SupervisorTest do
88
{:ok, supervisor: pid}
99
end
1010

11-
teardown config do
12-
Process.exit(config[:supervisor], :shutdown)
11+
setup do
12+
:error_logger.tty(false)
13+
on_exit fn -> :error_logger.tty(true) end
1314
:ok
1415
end
1516

lib/elixir/test/elixir/task_test.exs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ Code.require_file "test_helper.exs", __DIR__
33
defmodule TaskTest do
44
use ExUnit.Case, async: true
55

6+
setup do
7+
:error_logger.tty(false)
8+
on_exit fn -> :error_logger.tty(true) end
9+
:ok
10+
end
11+
612
def wait_and_send(caller, atom) do
713
receive do: (true -> true)
814
send caller, atom

0 commit comments

Comments
 (0)