singularity
Singularity is a registry for shared singleton actors, in Gleam.
When an actor’s process exits, it will be removed from the registry automatically. Fetching an actor using the require function will block until that actor has been registered. These two properties allow OTP supervisors to start your actors only when their dependencies are ready.
Example Usage
import actor_a
import actor_b
// Define a wrapper type for the actors (Subjects) you want register.
type Actors {
ActorA(Subject(actor_a.Message))
ActorB(Subject(actor_b.Message))
}
pub fn main() {
let assert Ok(registry) = singularity.start()
let assert Ok(actor_a_subj) = actor_a.start()
let assert Ok(actor_b_subj) = actor_b.start()
// Register the actors specifying your wrapper (`Actors`) variant.
singularity.register(registry, ActorA, actor_a_subj)
singularity.register(registry, ActorB, actor_b_subj)
// Retrieve registered actors, each will be returned via your
// wrapper type.
let assert ActorA(got_a) =
singularity.require(registry, ActorA, timeout_ms: 1000)
let assert ActorB(got_b) =
singularity.require(registry, ActorB, timeout_ms: 1000)
}
The example above is for illustrative purposes only; it will not compile. Please see the README and tests for concrete examples.
Types
A DelayFunc accepts two parameters:
- The uptime of the previous incarnation of this actor, in milliseconds.
- The previous delay in milliseconds, starting with 0.
pub type DelayFunc =
fn(Int, Int) -> Int
Functions
pub fn always_delay(ms delay: Int) -> fn(Int, Int) -> Int
Ignores inputs, always delays the same amount of time.
pub fn exponential_delay(
good_ms good: Int,
initial_ms initial: Int,
max_ms max: Option(Int),
) -> fn(Int, Int) -> Int
Starts at initial_ms, doubling with each subsequent call. If max_ms is provided, delay will not exceed that value. If the previous incarnation lived for at least good_ms, the delay will be reset to initial_ms.
pub fn register(
in actor: Subject(Message(a)),
key variant: fn(Subject(b)) -> a,
subject subj: Subject(b),
) -> Subject(b)
Registers an actor, using the actors wrapper type constructor as a key.
Registered actor processes will be monitored. Processes that exit will be removed from the registry automatically.
Returns the subject unchanged, for ease of use in pipelines.
pub fn require(
in actor: Subject(Message(a)),
key variant: fn(Subject(b)) -> a,
timeout_ms timeout: Int,
) -> a
Retrieves an actor, using the actors wrapper type constructor as a key. If
the actor is not present in the registry, the request will be retried
every 100ms for a total of timeout_ms
before crashing.
If your actors need to establish network connections during startup, consider using long (5000ms+) timeouts for them and any actors that depend on them.
pub fn restart_delay(
in actor: Subject(Message(a)),
key variant: fn(Subject(b)) -> a,
with func: fn(Int, Int) -> Int,
) -> Nil
Tracks and delays restarts for the actor key
using the provided
DelayFunc
.
See always_delay
and exponential_delay
for built-in delay functions,
or write your own for custom timings.
pub fn start() -> Result(Subject(Message(a)), StartError)
Starts the registry.
Note: Gleam actors are linked to the parent process by default.
pub fn stop(actor: Subject(Message(a))) -> Nil
Shuts down the registry. Does not affect registered actors.