Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased

- The `actor` module gains a `stop_abnormal` function

## v1.0.0-rc1 - 2025-05-16

- The `supervisor` module has been removed.
Expand Down
9 changes: 9 additions & 0 deletions src/gleam/otp/actor.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ pub fn stop() -> Next(state, message) {
Stop(process.Normal)
}

/// Indicate the actor is in a bad state and should shut down. It will not
/// handle any new messages, and any linked processes will also exit abnormally.
///
/// The provided reason will be given and propagated.
///
pub fn stop_abnormal(reason: Dynamic) -> Next(state, message) {
Stop(process.Abnormal(reason))
}

/// Provide a selector to change the messages that the actor is handling
/// going forward. This replaces any selector that was previously given
/// in the actor's `init` callback, or in any previous `Next` value.
Expand Down
26 changes: 26 additions & 0 deletions test/gleam/otp/actor_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,32 @@ pub fn killed_exit_can_be_trapped_test() {
|> should.equal(Ok(process.ExitMessage(actor.pid, process.Killed)))
}

pub fn abnormal_stop_exits_linked_test() {
process.trap_exits(True)
let exits =
process.new_selector()
|> process.select_trapped_exits(function.identity)

// Make an actor exit with an abnormal reason
let assert Ok(actor) =
actor.new(Nil)
|> actor.on_message(fn(_, _) { actor.stop_abnormal(dynamic.from("wibble")) })
|> actor.start

process.send(actor.data, "okay")

let trapped_reason = process.selector_receive(exits, 10)

// Stop trapping exits, as otherwise other tests fail
process.trap_exits(False)

// The weird reason below is because of https://github.com/gleam-lang/erlang/issues/66
trapped_reason
|> should.equal(
Ok(process.ExitMessage(actor.pid, process.Abnormal(dynamic.from("wibble")))),
)
}

fn mapped_selector(
selector: process.Selector(ActorMessage),
mapper: fn(a) -> ActorMessage,
Expand Down