actor

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 1, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package actor provides the owner-goroutine + inbox actor pattern: a single-writer aggregate that receives typed messages from any sender, drains them at known points, and never shares state across goroutines.

Three primitives compose: Mailbox (channel-based MPSC), Actor (Mailbox + Behavior loop), Supervisor (crash-isolated restart policy).

Index

Constants

This section is empty.

Variables

View Source
var ErrMailboxFull = errors.New("actor: mailbox full")

ErrMailboxFull is returned when a non-blocking Send is attempted on a full mailbox.

Functions

This section is empty.

Types

type Actor

type Actor[M, S any] struct {
	// contains filtered or unexported fields
}

Actor owns a goroutine, a mailbox, and Behavior-managed state.

func New

func New[M, S any](b Behavior[M, S], opts ...Option) *Actor[M, S]

New constructs an Actor; call Run to start it.

func (*Actor[M, S]) Run

func (a *Actor[M, S]) Run(ctx context.Context) error

Run drives the actor loop until ctx is cancelled. Returns the first error from Init/Handle/Tick/Close, or ctx.Err() on cancellation.

func (*Actor[M, S]) Send

func (a *Actor[M, S]) Send(ctx context.Context, msg M) error

Send delivers a message to the actor's mailbox.

type Behavior

type Behavior[M, S any] interface {
	Init(ctx context.Context) (S, error)
	Handle(ctx context.Context, state *S, msg M) error
	Tick(ctx context.Context, state *S, now time.Time) error
	Close(ctx context.Context, state *S) error
}

Behavior defines an Actor's lifecycle and message handling. State is owned by the Actor's goroutine and never escapes.

type LockFreeMailbox

type LockFreeMailbox[M any] struct {
	// contains filtered or unexported fields
}

LockFreeMailbox is a multi-producer / single-consumer mailbox backed by a power-of-two ring buffer with atomic head/tail. Producers reserve slots via CAS on the tail counter; the single consumer drains starting from the head counter.

Trade-offs vs Mailbox (channel-backed):

  • TrySend / Drain are lock-free and (when not blocked on the ring being full) faster than channel ops — typically 5-15 ns/op vs 50-100 ns for a buffered channel under contention.
  • The consumer MUST be a single goroutine (one Drain caller at a time). If you need multi-consumer semantics, use Mailbox.
  • Send is TrySend; there is no blocking Send. Producers handle full conditions explicitly (drop, retry, escalate).

Use when an actor's inbox is on a hot path and the producer count is bounded. Pair with kit/actor.Actor by passing a *LockFreeMailbox in place of *Mailbox (both have TrySend + Drain).

func NewLockFreeMailbox

func NewLockFreeMailbox[M any](capacity int) *LockFreeMailbox[M]

NewLockFreeMailbox returns a mailbox with the given capacity, rounded up to the next power of two (minimum 2).

func (*LockFreeMailbox[M]) Cap

func (mb *LockFreeMailbox[M]) Cap() int

Cap returns the rounded-up capacity.

func (*LockFreeMailbox[M]) Drain

func (mb *LockFreeMailbox[M]) Drain(buf *[]M)

Drain pulls every available message into *buf (reused for allocation- free polling). Single-consumer-only: do not call Drain from multiple goroutines concurrently.

func (*LockFreeMailbox[M]) Send

func (mb *LockFreeMailbox[M]) Send(ctx context.Context, msg M) error

Send is a blocking wrapper around TrySend that retries until success or context cancellation. Useful when the caller wants backpressure rather than ErrMailboxFull.

func (*LockFreeMailbox[M]) TrySend

func (mb *LockFreeMailbox[M]) TrySend(msg M) error

TrySend attempts to enqueue msg. Returns ErrMailboxFull if the ring is full. Lock-free; safe for many concurrent producers.

type Mailbox

type Mailbox[M any] struct {
	// contains filtered or unexported fields
}

Mailbox is an MPSC queue of messages of type M. Senders call Send (returns ErrMailboxFull if blocked); the owner calls Drain to bulk-pull.

func NewMailbox

func NewMailbox[M any](capacity int) *Mailbox[M]

NewMailbox returns a Mailbox with the given buffer capacity.

func (*Mailbox[M]) Cap

func (mb *Mailbox[M]) Cap() int

Cap returns the mailbox capacity.

func (*Mailbox[M]) Close

func (mb *Mailbox[M]) Close()

Close signals senders no more messages will be processed. After Close, Send panics; Drain still drains remaining messages.

func (*Mailbox[M]) Drain

func (mb *Mailbox[M]) Drain(buf *[]M)

Drain pulls all currently-available messages into the caller-supplied slice (reused for allocation-free polling). Returns when the channel is drained or ctx is cancelled.

func (*Mailbox[M]) Send

func (mb *Mailbox[M]) Send(ctx context.Context, msg M) error

Send delivers a message. Returns ErrMailboxFull if the mailbox is full and the context is not blocking, or ctx.Err() if cancelled.

func (*Mailbox[M]) TrySend

func (mb *Mailbox[M]) TrySend(msg M) error

TrySend attempts a non-blocking send.

type Option

type Option func(*config)

Option customises an Actor.

func WithMailboxCap

func WithMailboxCap(n int) Option

WithMailboxCap overrides the default mailbox capacity (256).

func WithTickEvery

func WithTickEvery(d time.Duration) Option

WithTickEvery enables a periodic Tick call at the given interval.

type RestartPolicy

type RestartPolicy struct {
	// Backoff is the duration to wait before restarting.
	Backoff time.Duration
	// MaxRestarts caps total restarts; 0 = unlimited.
	MaxRestarts int
}

RestartPolicy controls how a Supervisor responds to a child panic/error.

type Supervisor

type Supervisor struct {
	// contains filtered or unexported fields
}

Supervisor runs child goroutines, recovers panics, and restarts them according to policy.

func NewSupervisor

func NewSupervisor(policy RestartPolicy) *Supervisor

NewSupervisor returns a Supervisor with the given restart policy.

func (*Supervisor) Spawn

func (s *Supervisor) Spawn(ctx context.Context, name string, run func(ctx context.Context) error)

Spawn starts run in a managed goroutine. The supervisor recovers panics and restarts per policy until either ctx is cancelled or MaxRestarts is exceeded.

func (*Supervisor) Wait

func (s *Supervisor) Wait()

Wait blocks until every spawned child has exited.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL