Packages

Supervisor population control library

Current section

Files

Jump to
populator lib populator.ex
Raw

lib/populator.ex

require Populator.Helpers, as: H
defmodule Populator do
@doc """
It will update the given supervisor until it has the population demanded by
`desired_children`, either by creating new children or by killing existing
ones.
Every child created will be done so using the spec returned by
`child_spec`, so the `child_spec` function should end with a call to
`Supervisor.Spec.worker/3`. It should also register each worker with
a unique name.
The `desired_children` function should return a list of children data,
with all the state needed by the `child_spec` function for each of them.
It should include a `:name` with the unique name for each child.
`:ok` will be returned.
* `supervisor` is the supervisor name
* `child_spec` is a function returning a children spec given its child data
* `desired_children` is a function returning a list with data for each child
* `stationary` can be given to avoid the actual execution, useful on testing
environments, for example. `:stationary` will be returned.
See README.md for further details.
"""
def run(supervisor, child_spec, desired_children, opts \\ [])
when is_atom(supervisor)
and is_function(child_spec,1)
and is_function(desired_children,0) do
if opts[:stationary], do: :stationary,
else: populate(supervisor, child_spec, desired_children)
end
# Actually perform population operations
#
defp populate(supervisor, child_spec, desired_children) do
# start all desired children
desired = desired_children.()
for d <- desired do
{:ok, _} = child_spec.(d) |> H.start_child(supervisor)
end
# kill non desired ones
desired_names = desired |> Enum.map(&( &1[:name] )) |> Enum.sort
supervisor
|> H.children_names
|> Enum.filter(&( not(&1 in desired_names) ))
|> Enum.map(&( Process.whereis(&1) ))
|> Enum.each(&( true = Process.exit(&1, :kill) ))
:ok
end
end