Tideland Go Actor provides a lightweight implementation of the Actor model pattern for Go applications. The package ensures thread-safe operations by executing all actions sequentially in a dedicated background goroutine, eliminating the need for explicit locking mechanisms.
- Sequential Execution: All actions run in a dedicated goroutine
 - Operation Modes: Both synchronous and asynchronous execution
 - Timeout Control: Global and per-action timeouts
 - Queue Monitoring: Track queue status and capacity
 - Error Handling: Built-in panic recovery
 - Zero Dependencies: Pure Go implementation
 
go get tideland.dev/go/actorHere's a simple thread-safe counter implementation:
type Counter struct {
    value int
    act   *actor.Actor
}
func NewCounter() (*Counter, error) {
    // Create actor with default configuration
    cfg := actor.DefaultConfig()
    cfg.ActionTimeout = 5 * time.Second  // Default timeout for all actions
    
    act, err := actor.Go(cfg)
    if err != nil {
        return nil, err
    }
    return &Counter{act: act}, nil
}
// Increment asynchronously with timeout
func (c *Counter) Increment() error {
    return c.act.DoAsyncTimeout(time.Second, func() {
        c.value++
    })
}
// Value returns current count synchronously
func (c *Counter) Value() (int, error) {
    var v int
    err := c.act.DoSync(func() {
        v = c.value
    })
    return v, err
}
// Stop terminates the actor
func (c *Counter) Stop() {
    c.act.Stop()
}The actor package uses a Config struct for initialization:
cfg := actor.Config{
    Context:       ctx,               // Controls actor lifetime
    QueueCap:      1000,             // Action queue capacity
    ActionTimeout: 5 * time.Second,   // Default timeout for actions
    Recoverer:     func(r any) error {
        log.Printf("Panic: %v", r)
        return nil
    },
    Finalizer:     func(err error) error {
        if err != nil {
            log.Printf("Stopped: %v", err)
        }
        return err
    },
}
act, err := actor.Go(cfg)Monitor queue status to prevent overload:
status := act.QueueStatus()
fmt.Printf("Queue: %d/%d (full: %v)\n", 
    status.Length, status.Capacity, status.IsFull)Three ways to handle timeouts:
// 1. Global timeout in configuration
cfg := actor.DefaultConfig()
cfg.ActionTimeout = 5 * time.Second
// 2. Per-action timeout
err := act.DoSyncTimeout(2*time.Second, func() {
    // Operation with 2s timeout
})
// 3. Context timeout
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
err = act.DoSyncWithContext(ctx, func() {
    // Operation with context timeout
})- Keep Actions Small: Design actions to be quick and focused
 - Use Timeouts: Set appropriate timeouts to prevent hanging
 - Monitor Queue: Check queue status to prevent overload
 - Error Handling: Always check returned errors
 - Resource Management: Call 
Stop()when done 
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the BSD License - see the LICENSE file for details.
- Frank Mueller (https://github.com/themue / https://github.com/tideland / https://themue.dev)