Skip to content

Supervisor

gale_std.supervisor.Supervisor<Args> maps directly to Elixir.Supervisor. The implementation returns the same native init value as an Elixir callback and receives explicit @behaviour Supervisor and @impl Supervisor attributes. No macro or runtime supervisor module sits between the application and OTP.

An ordinary module implementing gale_std.gen_server.Server can be supervised as a native OTP child. Its typed call and cast protocols remain visible through the conventional child_spec/1 interface.

The child server exposes the conventional child_spec/1:

module supervisor.tally
implements gale_std.gen_server.Server<
Integer,
Integer,
TallyCall,
TallyCast,
Never,
Never
> as tally
pub type TallyCall = Count(reply_to: gale_std.gen_server.ReplyTo<Integer>)
pub type TallyCast = Bump
pub type TallyTarget = gale_std.gen_server.ServerTarget<tally>
pub fn start_link(initial: Integer) -> gale_std.gen_server.StartResult<tally> {
gale_std.gen_server.start_link(supervisor.tally, initial, [(:name, :tally)])
}
pub fn child_spec(initial: Integer) -> ChildSpec<tally> {
gale_std.gen_server.child_spec(supervisor.tally, initial, [(:id, :tally)])
}
pub fn value(server: TallyTarget) -> Integer {
gale_std.gen_server.call(server, fn(reply_to) => Count(reply_to))
}
pub fn bump(server: TallyTarget) -> :ok {
gale_std.gen_server.cast(server, Bump)
}
pub fn init(start: Integer) -> gale_std.otp.Init<Integer, Never> {
(:ok, start)
}
pub fn handle_call<R>(
build: fn(gale_std.gen_server.ReplyTo<R>) -> TallyCall,
from: gale_std.gen_server.ReplyTo<R>,
state: Integer
) -> gale_std.otp.Next<Integer, Never> {
match build(from) {
Count(reply_to) -> {
let _ = gale_std.gen_server.reply(reply_to, state)
let result: gale_std.otp.Next<Integer, Never> = (:noreply, state)
result
}
}
}
pub fn handle_cast(
message: TallyCast,
state: Integer
) -> gale_std.otp.Next<Integer, Never> {
match message {
Bump -> (:noreply, state + 1)
}
}

The supervisor is equally direct:

module supervisor.tally_supervisor
implements gale_std.supervisor.Supervisor<:ok>
pub fn start_link() -> gale_std.supervisor.SupervisorStartResult {
gale_std.supervisor.start_link(supervisor.tally_supervisor, :ok, [])
}
pub fn child_spec(args: :ok) -> ChildSpec<gale_std.supervisor.SupervisorService> {
gale_std.supervisor.child_spec(supervisor.tally_supervisor, args)
}
pub fn init(args: :ok) -> gale_std.supervisor.SupervisorInit {
gale_std.supervisor.init(
[gale_std.supervisor.any_child(supervisor.tally.child_spec(0))],
[(:strategy, :one_for_one)]
)
}

Child specs are native maps; options are native keyword tuples. Operations such as count_children, terminate_child, restart_child, and stop preserve Elixir’s normal results and exits.