1defmodule Supervisor.Spec do
2  @moduledoc """
3  Outdated functions for building child specifications.
4
5  The functions in this module are deprecated and they do not work
6  with the module-based child specs introduced in Elixir v1.5.
7  Please see the `Supervisor` documentation instead.
8
9  Convenience functions for defining supervisor specifications.
10
11  ## Example
12
13  By using the functions in this module one can specify the children
14  to be used under a supervisor, started with `Supervisor.start_link/2`:
15
16      import Supervisor.Spec
17
18      children = [
19        worker(MyWorker, [arg1, arg2, arg3]),
20        supervisor(MySupervisor, [arg1])
21      ]
22
23      Supervisor.start_link(children, strategy: :one_for_one)
24
25  Sometimes, it may be handy to define supervisors backed
26  by a module:
27
28      defmodule MySupervisor do
29        use Supervisor
30
31        def start_link(arg) do
32          Supervisor.start_link(__MODULE__, arg)
33        end
34
35        def init(arg) do
36          children = [
37            worker(MyWorker, [arg], restart: :temporary)
38          ]
39
40          supervise(children, strategy: :simple_one_for_one)
41        end
42      end
43
44  Note that in this case we don't have to explicitly import
45  `Supervisor.Spec` since `use Supervisor` automatically does so.
46  Defining a module-based supervisor can be useful, for example,
47  to perform initialization tasks in the `c:Supervisor.init/1` callback.
48
49  ## Supervisor and worker options
50
51  In the example above, we defined specs for workers and supervisors.
52  These specs (both for workers as well as supervisors) accept the
53  following options:
54
55    * `:id` - a name used to identify the child specification
56      internally by the supervisor; defaults to the given module
57      name for the child worker/supervisor
58
59    * `:function` - the function to invoke on the child to start it
60
61    * `:restart` - an atom that defines when a terminated child process should
62      be restarted (see the "Restart values" section below)
63
64    * `:shutdown` - an atom that defines how a child process should be
65      terminated (see the "Shutdown values" section below)
66
67    * `:modules` - it should be a list with one element `[module]`,
68      where module is the name of the callback module only if the
69      child process is a `Supervisor` or `GenServer`; if the child
70      process is a `GenEvent`, `:modules` should be `:dynamic`
71
72  ### Restart values (:restart)
73
74  The following restart values are supported in the `:restart` option:
75
76    * `:permanent` - the child process is always restarted
77
78    * `:temporary` - the child process is never restarted (not even
79      when the supervisor's strategy is `:rest_for_one` or `:one_for_all`)
80
81    * `:transient` - the child process is restarted only if it
82      terminates abnormally, i.e., with an exit reason other than
83      `:normal`, `:shutdown` or `{:shutdown, term}`
84
85  Note that supervisor that reached maximum restart intensity will exit with `:shutdown` reason.
86  In this case the supervisor will only restart if its child specification was defined with
87  the `:restart` option set to `:permanent` (the default).
88
89  ### Shutdown values (`:shutdown`)
90
91  The following shutdown values are supported in the `:shutdown` option:
92
93    * `:brutal_kill` - the child process is unconditionally terminated
94      using `Process.exit(child, :kill)`
95
96    * `:infinity` - if the child process is a supervisor, this is a mechanism
97      to give the subtree enough time to shut down; it can also be used with
98      workers with care
99
100    * a non-negative integer - the amount of time in milliseconds
101      that the supervisor tells the child process to terminate by calling
102      `Process.exit(child, :shutdown)` and then waits for an exit signal back.
103      If no exit signal is received within the specified time,
104      the child process is unconditionally terminated
105      using `Process.exit(child, :kill)`
106
107  """
108
109  @moduledoc deprecated:
110               "Use the new child specifications outlined in the Supervisor module instead"
111
112  @typedoc "Supported strategies"
113  @type strategy :: :simple_one_for_one | :one_for_one | :one_for_all | :rest_for_one
114
115  @typedoc "Supported restart values"
116  @type restart :: :permanent | :transient | :temporary
117
118  @typedoc "Supported shutdown values"
119  @type shutdown :: timeout | :brutal_kill
120
121  @typedoc "Supported worker values"
122  @type worker :: :worker | :supervisor
123
124  @typedoc "Supported module values"
125  @type modules :: :dynamic | [module]
126
127  @typedoc "Supported ID values"
128  @type child_id :: term
129
130  @typedoc "The supervisor specification"
131  @type spec ::
132          {child_id, start_fun :: {module, atom, [term]}, restart, shutdown, worker, modules}
133
134  @doc """
135  Receives a list of `children` (workers or supervisors) to
136  supervise and a set of `options`.
137
138  Returns a tuple containing the supervisor specification. This tuple can be
139  used as the return value of the `c:Supervisor.init/1` callback when implementing a
140  module-based supervisor.
141
142  ## Examples
143
144      supervise(children, strategy: :one_for_one)
145
146  ## Options
147
148    * `:strategy` - the restart strategy option. It can be either
149      `:one_for_one`, `:rest_for_one`, `:one_for_all`, or
150      `:simple_one_for_one`. You can learn more about strategies
151      in the `Supervisor` module docs.
152
153    * `:max_restarts` - the maximum number of restarts allowed in
154      a time frame. Defaults to `3`.
155
156    * `:max_seconds` - the time frame in which `:max_restarts` applies.
157      Defaults to `5`.
158
159  The `:strategy` option is required and by default a maximum of 3 restarts is
160  allowed within 5 seconds. Check the `Supervisor` module for a detailed
161  description of the available strategies.
162  """
163  @spec supervise(
164          [spec],
165          strategy: strategy,
166          max_restarts: non_neg_integer,
167          max_seconds: pos_integer
168        ) :: {:ok, tuple}
169  @deprecated "Use the new child specifications outlined in the Supervisor module instead"
170  def supervise(children, options) do
171    unless strategy = options[:strategy] do
172      raise ArgumentError, "expected :strategy option to be given"
173    end
174
175    maxR = Keyword.get(options, :max_restarts, 3)
176    maxS = Keyword.get(options, :max_seconds, 5)
177
178    assert_unique_ids(Enum.map(children, &get_id/1))
179    {:ok, {{strategy, maxR, maxS}, children}}
180  end
181
182  defp get_id({id, _, _, _, _, _}) do
183    id
184  end
185
186  defp get_id(other) do
187    raise ArgumentError,
188          "invalid tuple specification given to supervise/2. If you are trying to use " <>
189            "the map child specification that is part of the Elixir v1.5, use Supervisor.init/2 " <>
190            "instead of Supervisor.Spec.supervise/2. See the Supervisor module for more information. " <>
191            "Got: #{inspect(other)}"
192  end
193
194  defp assert_unique_ids([id | rest]) do
195    if id in rest do
196      raise ArgumentError,
197            "duplicated ID #{inspect(id)} found in the supervisor specification, " <>
198              "please explicitly pass the :id option when defining this worker/supervisor"
199    else
200      assert_unique_ids(rest)
201    end
202  end
203
204  defp assert_unique_ids([]) do
205    :ok
206  end
207
208  @doc """
209  Defines the given `module` as a worker which will be started
210  with the given arguments.
211
212      worker(ExUnit.Runner, [], restart: :permanent)
213
214  By default, the function `start_link` is invoked on the given
215  module. Overall, the default values for the options are:
216
217      [
218        id: module,
219        function: :start_link,
220        restart: :permanent,
221        shutdown: 5000,
222        modules: [module]
223      ]
224
225  See the "Supervisor and worker options" section in the `Supervisor.Spec` module for more
226  information on the available options.
227  """
228  @spec worker(
229          module,
230          [term],
231          restart: restart,
232          shutdown: shutdown,
233          id: term,
234          function: atom,
235          modules: modules
236        ) :: spec
237  @deprecated "Use the new child specifications outlined in the Supervisor module instead"
238  def worker(module, args, options \\ []) do
239    child(:worker, module, args, options)
240  end
241
242  @doc """
243  Defines the given `module` as a supervisor which will be started
244  with the given arguments.
245
246      supervisor(module, [], restart: :permanent)
247
248  By default, the function `start_link` is invoked on the given
249  module. Overall, the default values for the options are:
250
251      [
252        id: module,
253        function: :start_link,
254        restart: :permanent,
255        shutdown: :infinity,
256        modules: [module]
257      ]
258
259  See the "Supervisor and worker options" section in the `Supervisor.Spec` module for more
260  information on the available options.
261  """
262  @spec supervisor(
263          module,
264          [term],
265          restart: restart,
266          shutdown: shutdown,
267          id: term,
268          function: atom,
269          modules: modules
270        ) :: spec
271  @deprecated "Use the new child specifications outlined in the Supervisor module instead"
272  def supervisor(module, args, options \\ []) do
273    options = Keyword.put_new(options, :shutdown, :infinity)
274    child(:supervisor, module, args, options)
275  end
276
277  defp child(type, module, args, options) do
278    id = Keyword.get(options, :id, module)
279    modules = Keyword.get(options, :modules, modules(module))
280    function = Keyword.get(options, :function, :start_link)
281    restart = Keyword.get(options, :restart, :permanent)
282    shutdown = Keyword.get(options, :shutdown, 5000)
283
284    {id, {module, function, args}, restart, shutdown, type, modules}
285  end
286
287  defp modules(GenEvent), do: :dynamic
288  defp modules(module), do: [module]
289end
290