Current section
Files
Jump to
Current section
Files
src/gleam/otp/supervision.gleam
import gleam/otp/actor
/// Restart defines when a terminated child process must be restarted.
pub type Restart {
/// A permanent child process is always restarted.
Permanent
/// A transient child process is restarted only if it terminates abnormally,
/// that is, with another exit reason than `normal`, `shutdown`, or
/// `{shutdown,Term}`.
Transient
/// A temporary child process is never restarted (even when the supervisor's
/// restart strategy is `RestForOne` or `OneForAll` and a sibling's death
/// causes the temporary process to be terminated).
Temporary
}
pub type ChildType {
/// A worker child has to shut-down within a given amount of time.
Worker(
/// The number of milliseconds the child is given to shut down. The
/// supervisor tells the child process to terminate by calling
/// `exit(Child,shutdown)` and then wait for an exit signal with reason
/// shutdown back from the child process. If no exit signal is received
/// within the specified number of milliseconds, the child process is
/// unconditionally terminated using `exit(Child,kill)`.
shutdown_ms: Int,
)
Supervisor
}
/// A description a how to start a new child process under an OTP supervisor.
pub type ChildSpecification(data) {
ChildSpecification(
/// A function to call to start the child process.
start: fn() -> Result(actor.Started(data), actor.StartError),
/// When the child is to be restarted. See the `Restart` documentation for
/// more.
///
/// You most likely want the `Permanent` variant.
restart: Restart,
/// This defines if a child is considered significant for automatic
/// self-shutdown of the supervisor.
///
/// You most likely do not want to consider any children significant.
///
/// This will be ignored if the supervisor auto shutdown is set to `Never`,
/// which is the default.
significant: Bool,
/// Whether the child is a supervisor or not.
child_type: ChildType,
)
}
/// A regular child process.
///
/// You should use this unless your process is also a supervisor.
///
/// The default shutdown timeout is 5000ms. This can be changed with the
/// `timeout` function.
///
pub fn worker(
run start: fn() -> Result(actor.Started(data), actor.StartError),
) -> ChildSpecification(data) {
ChildSpecification(
start:,
restart: Permanent,
significant: False,
child_type: Worker(5000),
)
}
/// A special child that is a supervisor itself.
///
/// Supervisor children have an unlimited shutdown time, there is no timeout.
///
pub fn supervisor(
run start: fn() -> Result(actor.Started(data), actor.StartError),
) -> ChildSpecification(data) {
ChildSpecification(
start:,
restart: Permanent,
significant: False,
child_type: Supervisor,
)
}
/// This defines if a child is considered significant for automatic
/// self-shutdown of the supervisor.
///
/// You most likely do not want to consider any children significant.
///
/// This will be ignored if the supervisor auto shutdown is set to `Never`,
/// which is the default.
///
/// The default value for significance is `False`.
pub fn significant(
child: ChildSpecification(data),
significant: Bool,
) -> ChildSpecification(data) {
ChildSpecification(..child, significant: significant)
}
/// This defines the amount of milliseconds a child has to shut down before
/// being brutal killed by the supervisor.
///
/// If not set the default for a child is 5000ms.
///
/// This will be ignored if the child is a supervisor itself.
///
pub fn timeout(
child: ChildSpecification(data),
ms ms: Int,
) -> ChildSpecification(data) {
case child.child_type {
Worker(_) -> ChildSpecification(..child, child_type: Worker(ms))
_ -> child
}
}
/// When the child is to be restarted. See the `Restart` documentation for
/// more.
///
/// The default value for restart is `Permanent`.
pub fn restart(
child: ChildSpecification(data),
restart: Restart,
) -> ChildSpecification(data) {
ChildSpecification(..child, restart: restart)
}
/// Transform the data of the started child process.
///
pub fn map_data(
child: ChildSpecification(a),
transform: fn(a) -> b,
) -> ChildSpecification(b) {
ChildSpecification(..child, start: fn() {
case child.start() {
Ok(started) -> Ok(actor.Started(..started, data: transform(started.data)))
Error(e) -> Error(e)
}
})
}