11 Commits
Author SHA1 Message Date
Olaoluwa Osuntokun c11c192b3f Merge pull request #10142 from Roasbeef/actor-mailbox-v2
actor: add new abstraction over mailbox
2026-02-17 17:27:45 -08:00
Olaoluwa Osuntokun ba1fb50380 build+docs: bump minimum Go version to 1.25.5
With Go 1.26 now released, this bumps the minimum required Go version
from 1.24.11 to 1.25.5 across all go.mod files and updates the
installation documentation with the correct download links and SHA256
hashes for Go 1.25.5 binaries.

The build system (Dockerfiles, Makefile, CI) was already using Go 1.25.5,
so this change aligns the go.mod minimum version to match.
2026-02-10 12:54:10 -08:00
Olaoluwa Osuntokun 20c5c9d6be actor: refactor Actor to use Mailbox interface
This commit refactors the Actor implementation to use the new Mailbox
interface instead of directly managing a channel. This change
significantly simplifies the actor's message processing loop and
improves separation of concerns.

The main changes include replacing the direct channel field with a
Mailbox interface, updating NewActor to create a ChannelMailbox
instance, and refactoring the process method to use the iterator
pattern provided by mailbox.Receive. The new implementation uses a
clean for-range loop over the mailbox's message iterator, eliminating
the complex select statement that previously handled both message
reception and context cancellation.

The Tell and Ask methods in actorRefImpl have been simplified to use
the mailbox's Send method, which internally handles both the caller's
context and the actor's context. This eliminates the need for complex
select statements in these methods and ensures consistent context
handling throughout the actor system.

Message draining during shutdown is now handled through the mailbox's
Drain method, providing a cleaner separation between normal message
processing and cleanup operations. The actor still properly sends
unprocessed messages to the Dead Letter Office and completes pending
promises with appropriate errors during shutdown.
2026-02-09 19:39:06 -08:00
Olaoluwa Osuntokun de7b0e1dd4 actor: add tests for mailbox implementation
This commit adds thorough test coverage for the new Mailbox interface
and ChannelMailbox implementation. The tests verify correct behavior
across various scenarios including successful sends, context
cancellation, mailbox closure, and concurrent operations.

The test suite specifically validates that the mailbox respects both
the caller's context and the actor's context during send and receive
operations. This ensures that actors properly shut down when their
context is cancelled, and that callers can cancel operations without
affecting the actor's lifecycle.

Additional tests cover edge cases such as zero-capacity mailboxes
(which default to a capacity of 1), draining messages after closure,
and concurrent sends from multiple goroutines. The concurrent test
uses 10 senders each sending 100 messages to verify thread-safety
and proper message ordering.

All tests pass with the race detector enabled, confirming the
implementation is free from data races.
2026-02-09 17:03:24 -08:00
Olaoluwa Osuntokun 30af28104b actor: introduce generic Mailbox interface with iter.Seq support
This commit introduces a new Mailbox interface that abstracts the
message queue implementation for actors. Previously, actors used a
direct channel for their mailbox, which limited flexibility and made
it difficult to implement alternative mailbox strategies.

The new Mailbox interface provides methods for sending, receiving, and
draining messages, with full context support for cancellation. The
Receive method leverages Go 1.23's iter.Seq pattern, providing a clean
iterator-based API that allows natural for-range loops over messages.

The ChannelMailbox implementation maintains the existing channel-based
behavior while conforming to the new interface. It stores the actor's
context internally, ensuring both caller and actor contexts are
properly respected during send and receive operations. This simplifies
context handling compared to complex context merging approaches.

This abstraction enables future implementations such as priority
mailboxes, persistent mailboxes, or bounded mailboxes with overflow
strategies, without requiring changes to the actor implementation.
2026-02-09 17:03:24 -08:00
Olaoluwa Osuntokun 8781daa995 actor: add README.md
In this commit, we add a readme which serves as a general introduction
to the pacakge, and also the motivation of the package. It serves as a
manual for developers that may wish to interact with the package.
2026-02-06 19:26:54 -08:00
Olaoluwa Osuntokun 7c9d72134c actor: add example files
In this commit, we add a series of examples that show how the package
can be used in the wild. They can be run as normal Example tests.
2026-02-06 19:26:54 -08:00
Olaoluwa Osuntokun 9ebd8d240d actor: add the actor system and router
In this commit, we add the actor system (along with the receiptionist)
and the router.

An actor can be registered with the system, which allows other callers
to locate it to send message to it via the receptionist. Custom routers
can be created for when there're actors that rely on the same service
key and also req+resp type. This can be used to implement something
similar to a worker pool.
2026-02-06 19:26:54 -08:00
Olaoluwa Osuntokun b055af6420 actor: add fundamental interfaces and concrete Actor impl
In this commit, we add the actual Actor implementation. We define a
series of types and interfaces, that in concert, describe our actor. An
actor has some ID, a reference (used to send messages to it), and also a
set of defined messages that it'll accept.

An actor can be implemented using a simple function if it's stateless.
Otherwise, a struct can implement the Receive method, and handle its
internal message passing and state that way.
2026-02-06 19:26:54 -08:00
Olaoluwa Osuntokun 3069829d61 actor: add Future[T] and Promise[T] w/ concrete impls
In this commit, we add two new fundamental data structures: Future[T]
and Promise[T].

A future is a response that might be ready at some point in the future.
This is already a common pattern in Go, we just make a type safe wrapper
around the typical operations: block w/ a timeout, add a call back for
execution, pipeline the response to a new future.

A promise is an intent to complete a future. Typically the caller
receives the future, and the callee is able to complete the future using
a promise.
2026-02-06 19:26:54 -08:00
Olaoluwa Osuntokun 90415aaa04 actor: add new actor package as distinct sub-module 2026-02-06 19:26:53 -08:00