Dynamic Supervisor
An Erlang library providing a supervisor optimized for dynamically spawning children. This is a port of Elixir's DynamicSupervisor, maintaining a similar API while following Erlang conventions.
Installation
Add to your rebar.config:
{deps, [
{dynamic_supervisor, "1.0.0"}
]}.Or for hex.pm:
{deps, [
{dynamic_supervisor, {hex, dynamic_supervisor, "1.0.0"}}
]}.Overview
The dynamic_supervisor module provides a supervisor optimized for dynamically starting children. Unlike the standard supervisor which is designed for static children started in order, a dynamic supervisor:
- Starts with no children
-
Allows starting children on demand via
start_child/2 - Has no ordering between children
- Can efficiently handle millions of children
- Executes operations like shutdown concurrently
Features
- One-for-one supervision strategy: Only the failed child is restarted
- Dynamic child management: Add and remove children at runtime
- Restart strategies: Support for
permanent,transient, andtemporaryrestart types - Maximum children limit: Optional limit on the number of concurrent children
- Extra arguments: Arguments that are prepended to child start arguments
- Full OTP compliance: Implements standard supervisor behaviors
API
Starting a Dynamic Supervisor
{ok, Pid} = dynamic_supervisor:start_link([
{name, {local, my_supervisor}},
{strategy, one_for_one},
{max_restarts, 3},
{max_seconds, 5},
{max_children, 1000}
]).Starting Children
%% Full child specification
{ok, ChildPid} = dynamic_supervisor:start_child(my_supervisor,
#{id => worker1,
start => {my_worker, start_link, [Arg1, Arg2]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [my_worker]}).
%% Simplified specification (using defaults)
{ok, ChildPid2} = dynamic_supervisor:start_child(my_supervisor,
#{id => worker2,
start => {my_worker, start_link, []}}).Managing Children
%% List all children
Children = dynamic_supervisor:which_children(my_supervisor).
%% Count children
Counts = dynamic_supervisor:count_children(my_supervisor).
%% Returns: #{specs => N, active => N, supervisors => N, workers => N}
%% Terminate a specific child
ok = dynamic_supervisor:terminate_child(my_supervisor, ChildPid).
%% Stop the supervisor
ok = dynamic_supervisor:stop(my_supervisor).Examples
Basic Usage
See example_usage.erl for a complete example:
make exampleRunning Tests
make testInteractive Shell
make shellThen in the Erlang shell, you need to add the examples path:
1> code:add_path("examples").
2> example_usage:demo().Differences from Elixir's DynamicSupervisor
- Module naming: Uses Erlang convention (
dynamic_supervisorinstead ofDynamicSupervisor) - Options format: Uses proplist format
[{key, value}]instead of keyword lists - Child specs: Supports both map-based specs and traditional tuple-based specs
- Return values: Uses standard Erlang return conventions
- Error handling: Uses Erlang's error_logger instead of Elixir's Logger
Implementation Notes
- Built on top of gen_server behavior
- Uses maps for efficient child storage
- Implements OTP supervisor protocols
-
Supports hot code upgrades via
code_change/3 - Proper cleanup on termination with concurrent child shutdown
Files
src/dynamic_supervisor.erl- Main implementationexamples/counter.erl- Example gen_server for demonstrationsexamples/example_usage.erl- Usage examplestest/- Test suites (EUnit and Common Test)Makefile- Build automation
Building
make compile # Compile the library
make test # Run tests
make example # Run example
make shell # Start Erlang shellRequirements
- Erlang/OTP 21 or later (for map support)
- rebar3 (for building)
License
Apache 2.0 - This implementation follows the structure of Elixir's DynamicSupervisor but is written entirely in Erlang.