Reentrancy

Overview

Reentrancy is the ability of an actor to process new messages while it is waiting for a response from another actor. In the default, non-reentrant model, an actor handles one message at a time: if it sends a request and waits for a reply, its mailbox is effectively blocked until that reply arrives. With reentrancy enabled, the actor can keep processing other messages and handle the reply later via a continuation (callback), so the mailbox stays responsive.

The default: one message at a time

In the actor model, each actor has a mailbox and processes messages sequentially. That gives you a simple mental model and avoids races on the actor’s state. As long as the handler runs to completion without waiting on external replies, this works well. The problem appears when an actor needs to ask another actor for something: if it blocks until the response comes back, it cannot process any other message in the meantime. The actor (and its mailbox) is stuck until the response arrives or times out.

What reentrancy changes

When reentrancy is enabled, the actor can issue an async request to another actor and register a continuation. The runtime does not block the actor’s message loop: as soon as the request is sent, the actor can move on to the next message. When the response (or error) arrives, the runtime invokes the continuation with that result. So the actor can have multiple requests in flight and still process new messages; responses are handled by their continuations, not by blocking in the middle of a handler.

In other words

With reentrancy, an actor can:

  • Send async requests to other actors (Request or RequestName)

  • Continue processing new messages while waiting for responses

  • Handle responses via continuations (callbacks) when they arrive

  • Avoid blocking the mailbox on request–response round-trips

Without reentrancy, the actor processes messages strictly one at a time; if it waits for a reply, nothing else is processed until that reply (or timeout). With reentrancy, multiple pending requests can be outstanding and the actor remains responsive to new work.

Trade-off

Reentrancy trades strict single-threaded-by-message safety for better concurrency and responsiveness. While a continuation is running, the actor’s state may have changed because other messages were processed in between. You must design your continuations with that in mind (e.g. avoid assuming state that might be stale, or use request correlation ids to match responses to the right logical operation). When used carefully, reentrancy lets you build responsive actors that coordinate with others without blocking the mailbox.

Importance

Traditional actor model (no reentrancy):

With reentrancy:

Benefits:

  • Higher throughput: Don't block on async operations

  • Better resource utilization: Process messages while waiting

  • Responsive actors: Handle new messages immediately

  • Concurrent workflows: Multiple requests in flight

Modes

GoAkt provides three reentrancy modes:

Off (Default)

No reentrancy support. Async requests not allowed.

AllowAll

Allow concurrent request handling. New messages processed while requests pending.

Behavior:

  • Multiple async requests can be in flight

  • New messages processed immediately

  • Continuations run when responses arrive

  • No ordering guarantees for completion

Use when:

  • Order of completion doesn't matter

  • Higher throughput needed

  • Independent requests

  • Stateless operations

StashNonReentrant

Behavior:

  • One request at a time

  • New messages stashed until request completes

  • Continuations run when response arrives

  • Sequential processing maintained

Use when:

  • Order matters

  • Stateful operations

  • Need sequential consistency

  • Avoid race conditions

Get Started

Reentrancy is enabled for actor during their creation using the WithReentrancyarrow-up-right SpawnOption.

Once the reentrancy option is properly configured, the feature can be used through the following methods available on the ReceiveContext:

  • Request: A non-blocking counterpart of Ask. This method can only be used locally or within a single-node actor system.

  • RequestName: Similar to Request, but location-transparent.

Example

Request Options

Timeout

This help to set timeout for individual requests:

Reentrancy Mode

This helps override reentrancy mode for specific requests:

Cancellation

Inflight reentrant requests can be cancelled:

Best Practices

  1. Handle errors in continuations

  2. Set request timeouts

  3. Cancel requests when no longer needed

  4. Use appropriate reentrancy mode

  5. Keep continuations short

  6. Don't block in continuations

  7. Don't forget error handling

  8. Don't use without timeouts

  9. Don't access actor state unsafely

  10. Don't leak request handles

Common Pitfalls

Reentrancy often causes bugs that are:

  • Hard to reproduce

  • Sensitive to timing

  • Mistaken for β€œdistributed system issues”

Typical mistakes include:

  • Assuming state is unchanged after an await

  • Updating shared state in multiple message handlers

  • Performing multi-step workflows without protection

These bugs are logical, not technical β€” the system is doing exactly what it was told.

Last updated