Skip to content

Commit fcb6e45

Browse files
committed
Add support for automatic shutdown to Supervisor
1 parent 2244a2f commit fcb6e45

File tree

2 files changed

+59
-8
lines changed

2 files changed

+59
-8
lines changed

lib/elixir/lib/supervisor.ex

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ defmodule Supervisor do
145145
and such. It is set automatically based on the `:start` value and it is rarely
146146
changed in practice.
147147
148+
* `:significant` - a boolean indicating if the child process should be
149+
considered significant with regard to automatic shutdown. Only `:transient`
150+
and `:temporary` child processes can be marked as significant. This key is
151+
optional and defaults to `false`. See section "Automatic shutdown" below
152+
for more details.
153+
148154
Let's understand what the `:shutdown` and `:restart` options control.
149155
150156
### Shutdown values (:shutdown)
@@ -302,6 +308,10 @@ defmodule Supervisor do
302308
* `:max_seconds` - the time frame in which `:max_restarts` applies.
303309
Defaults to `5`.
304310
311+
* `:auto_shutdown` - the automatic shutdown option. It can be
312+
`:never`, `:any_significant`, or `:all_significant`. Optional.
313+
See the "Automatic shutdown" section.
314+
305315
* `:name` - a name to register the supervisor process. Supported values are
306316
explained in the "Name registration" section in the documentation for
307317
`GenServer`. Optional.
@@ -327,6 +337,27 @@ defmodule Supervisor do
327337
328338
To efficiently supervise children started dynamically, see `DynamicSupervisor`.
329339
340+
### Automatic shutdown
341+
342+
Supervisors have the ability to automatically shut themselves down when child
343+
processes marked as `:significant` exit.
344+
345+
Supervisors support different automatic shutdown options (through
346+
the `:auto_shutdown` option, as seen above):
347+
348+
* `:never` - this is the default, automatic shutdown is disabled.
349+
350+
* `:any_significant` - if any significant child process exits, the supervisor
351+
will automatically shut down its children, then itself.
352+
353+
* `:all_significant` - when all significant child processes have exited,
354+
the supervisor will automatically shut down its children, then itself.
355+
356+
Only `:transient` and `:temporary` child processes can be marked as significant,
357+
and this configuration affects the behavior. Significant `:transient` child
358+
processes must exit normally for automatic shutdown to be considered, where
359+
`:temporary` child processes may exit for any reason.
360+
330361
### Name registration
331362
332363
A supervisor is bound to the same name registration rules as a `GenServer`.
@@ -521,7 +552,8 @@ defmodule Supervisor do
521552
@type sup_flags() :: %{
522553
strategy: strategy(),
523554
intensity: non_neg_integer(),
524-
period: pos_integer()
555+
period: pos_integer(),
556+
auto_shutdown: auto_shutdown()
525557
}
526558

527559
@typedoc "The supervisor reference"
@@ -532,6 +564,7 @@ defmodule Supervisor do
532564
{:strategy, strategy}
533565
| {:max_restarts, non_neg_integer}
534566
| {:max_seconds, pos_integer}
567+
| {:auto_shutdown, auto_shutdown}
535568

536569
@typedoc "Supported restart options"
537570
@type restart :: :permanent | :transient | :temporary
@@ -542,6 +575,9 @@ defmodule Supervisor do
542575
@typedoc "Supported strategies"
543576
@type strategy :: :one_for_one | :one_for_all | :rest_for_one
544577

578+
@typedoc "Supported automatic shutdown options"
579+
@type auto_shutdown :: :never | :any_significant | :all_significant
580+
545581
@typedoc """
546582
Supervisor type.
547583
@@ -561,7 +597,8 @@ defmodule Supervisor do
561597
optional(:restart) => restart(),
562598
optional(:shutdown) => shutdown(),
563599
optional(:type) => type(),
564-
optional(:modules) => [module()] | :dynamic
600+
optional(:modules) => [module()] | :dynamic,
601+
optional(:significant) => boolean()
565602
}
566603

567604
@doc """
@@ -611,7 +648,9 @@ defmodule Supervisor do
611648
[option | init_option]
612649
) :: {:ok, pid} | {:error, {:already_started, pid} | {:shutdown, term} | term}
613650
def start_link(children, options) when is_list(children) do
614-
{sup_opts, start_opts} = Keyword.split(options, [:strategy, :max_seconds, :max_restarts])
651+
{sup_opts, start_opts} =
652+
Keyword.split(options, [:strategy, :max_seconds, :max_restarts, :auto_shutdown])
653+
615654
start_link(Supervisor.Default, init(children, sup_opts), start_opts)
616655
end
617656

@@ -646,6 +685,9 @@ defmodule Supervisor do
646685
* `:max_seconds` - the time frame in seconds in which `:max_restarts`
647686
applies. Defaults to `5`.
648687
688+
* `:auto_shutdown` - the automatic shutdown option. It can be either
689+
`:never`, `:any_significant`, or `:all_significant`
690+
649691
The `:strategy` option is required and by default a maximum of 3 restarts
650692
is allowed within 5 seconds. Check the `Supervisor` module for a detailed
651693
description of the available strategies.
@@ -681,7 +723,15 @@ defmodule Supervisor do
681723

682724
intensity = Keyword.get(options, :max_restarts, 3)
683725
period = Keyword.get(options, :max_seconds, 5)
684-
flags = %{strategy: strategy, intensity: intensity, period: period}
726+
auto_shutdown = Keyword.get(options, :auto_shutdown, :never)
727+
728+
flags = %{
729+
strategy: strategy,
730+
intensity: intensity,
731+
period: period,
732+
auto_shutdown: auto_shutdown
733+
}
734+
685735
{:ok, {flags, Enum.map(children, &init_child/1)}}
686736
end
687737

@@ -805,7 +855,8 @@ defmodule Supervisor do
805855

806856
def child_spec(module_or_map, overrides) do
807857
Enum.reduce(overrides, init_child(module_or_map), fn
808-
{key, value}, acc when key in [:id, :start, :restart, :shutdown, :type, :modules] ->
858+
{key, value}, acc
859+
when key in [:id, :start, :restart, :shutdown, :type, :modules, :significant] ->
809860
Map.put(acc, key, value)
810861

811862
{key, _value}, _acc ->

lib/elixir/test/elixir/supervisor_test.exs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,11 @@ defmodule SupervisorTest do
106106
end
107107

108108
test "init/2" do
109-
flags = %{intensity: 3, period: 5, strategy: :one_for_one}
109+
flags = %{intensity: 3, period: 5, strategy: :one_for_one, auto_shutdown: :never}
110110
children = [%{id: Task, restart: :temporary, start: {Task, :start_link, [[]]}}]
111111
assert Supervisor.init([Task], strategy: :one_for_one) == {:ok, {flags, children}}
112112

113-
flags = %{intensity: 1, period: 2, strategy: :one_for_all}
113+
flags = %{intensity: 1, period: 2, strategy: :one_for_all, auto_shutdown: :never}
114114
children = [%{id: Task, restart: :temporary, start: {Task, :start_link, [:foo]}}]
115115

116116
assert Supervisor.init(
@@ -126,7 +126,7 @@ defmodule SupervisorTest do
126126
end
127127

128128
test "init/2 with old and new child specs" do
129-
flags = %{intensity: 3, period: 5, strategy: :one_for_one}
129+
flags = %{intensity: 3, period: 5, strategy: :one_for_one, auto_shutdown: :never}
130130

131131
children = [
132132
%{id: Task, restart: :temporary, start: {Task, :start_link, [[]]}},

0 commit comments

Comments
 (0)