actor

package module
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: May 25, 2025 License: BSD-3-Clause Imports: 4 Imported by: 0

README

Tideland Go Actor

GitHub release GitHub license Go Module GoDoc Workflow Go Report Card

Description

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.

Key Features
  • 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

Installation

go get tideland.dev/go/actor

Quick Start

Here'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()
}

Configuration

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)

Queue Monitoring

Monitor queue status to prevent overload:

status := act.QueueStatus()
fmt.Printf("Queue: %d/%d (full: %v)\n", 
    status.Length, status.Capacity, status.IsFull)

Timeout Handling

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
})

Best Practices

  1. Keep Actions Small: Design actions to be quick and focused
  2. Use Timeouts: Set appropriate timeouts to prevent hanging
  3. Monitor Queue: Check queue status to prevent overload
  4. Error Handling: Always check returned errors
  5. Resource Management: Call Stop() when done

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the BSD License - see the LICENSE file for details.

Contributors

Documentation

Overview

Package actor provides a robust implementation of the Actor model pattern for concurrent programming in Go. It enables safe and efficient concurrent operations by ensuring that all actions on shared state are executed sequentially in a dedicated background goroutine.

Key Features:

  • Sequential execution of actions in a background goroutine
  • Support for both synchronous and asynchronous operations
  • Built-in panic recovery and error handling
  • Context-based cancellation support
  • Action timeouts (global and per-action)
  • Queue monitoring capabilities

Basic Usage:

type Counter struct {
	value int
	act   *actor.Actor
}

func NewCounter() (*Counter, error) {
	cfg := actor.DefaultConfig()
	act, err := actor.Go(cfg)
	if err != nil {
		return nil, err
	}
	return &Counter{act: act}, nil
}

// Asynchronous increment
func (c *Counter) Increment() error {
	return c.act.DoAsync(func() {
		c.value++
	})
}

// Synchronous read with timeout
func (c *Counter) Value() (int, error) {
	var v int
	err := c.act.DoSyncTimeout(time.Second, func() {
		v = c.value
	})
	return v, err
}

Configuration:

cfg := actor.Config{
	Context:       ctx,               // Custom context
	QueueCap:      1000,             // Queue capacity
	ActionTimeout: 5 * time.Second,   // Default timeout
	Recoverer: func(r any) error {
		log.Printf("Panic: %v", r)
		return nil
	},
	Finalizer: func(err error) error {
		if err != nil {
			log.Printf("Stopped with: %v", err)
		}
		return err
	},
}

Queue Monitoring:

status := act.QueueStatus()
if status.IsFull {
	log.Printf("Queue at capacity: %d/%d", status.Length, status.Capacity)
}

Timeout Handling:

// Global timeout via config
cfg := actor.DefaultConfig()
cfg.ActionTimeout = 5 * time.Second
act, _ := actor.Go(cfg)

// Per-action timeout
err := act.DoSyncTimeout(time.Second, func() {
	// Operation with 1s timeout
})

// Context timeout
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
err = act.DoSyncWithContext(ctx, func() {
	// Operation with context timeout
})

The actor package is particularly useful when building concurrent applications that need to maintain consistent state without explicit locking mechanisms. It helps prevent race conditions and makes concurrent code easier to reason about by centralizing state modifications in a single goroutine.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Action

type Action func()

Action defines the signature of an actor action.

type Actor

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

func Go

func Go(cfg Config) (*Actor, error)

Go starts an Actor with the given configuration.

func (*Actor) DoAsync

func (act *Actor) DoAsync(action Action) error

DoAsync sends the actor function to the backend goroutine and returns when it's queued.

func (*Actor) DoAsyncTimeout

func (act *Actor) DoAsyncTimeout(timeout time.Duration, action Action) error

DoAsyncTimeout sends the action to the backend with a specific timeout

func (*Actor) DoAsyncWithContext added in v0.3.0

func (act *Actor) DoAsyncWithContext(ctx context.Context, action Action) error

DoAsyncWithContext sends the actor function to the backend and returns when it's queued. A context allows to cancel the action or add a timeout.

func (*Actor) DoSync

func (act *Actor) DoSync(action Action) error

DoSync executes the actor function and returns when it's done.

func (*Actor) DoSyncTimeout

func (act *Actor) DoSyncTimeout(timeout time.Duration, action Action) error

DoSyncTimeout executes the action with a specific timeout

func (*Actor) DoSyncWithContext added in v0.3.0

func (act *Actor) DoSyncWithContext(ctx context.Context, action Action) error

DoSyncWithContext executes the action and returns when it's done. A context allows to cancel the action or add a timeout.

func (*Actor) Done added in v0.3.0

func (act *Actor) Done() <-chan struct{}

Done returns a channel that is closed when the Actor terminates.

func (*Actor) Err

func (act *Actor) Err() error

Err returns information if the Actor has an error.

func (*Actor) IsDone added in v0.3.0

func (act *Actor) IsDone() bool

IsDone allows to simply check if the Actor is done in a select or if statement.

func (*Actor) QueueStatus added in v0.5.0

func (act *Actor) QueueStatus() QueueStatus

QueueStatus returns the current status of the action queue

func (*Actor) Repeat added in v0.3.0

func (act *Actor) Repeat(
	interval time.Duration,
	action Action) (func(), error)

Repeat runs an Action in a given interval. It will be done asynchronously until the returned stopper function is called or the Actor is stopped.

func (*Actor) RepeatWithContext added in v0.3.0

func (act *Actor) RepeatWithContext(
	ctx context.Context,
	interval time.Duration,
	action Action) (func(), error)

RepeatWithContext runs an Action in a given interval. It will be done asynchronously until the context is canceled or timeout, the returned stopper function is called or the Actor is stopped.

func (*Actor) Stop

func (act *Actor) Stop()

Stop terminates the Actor backend.

type ActorError added in v0.4.0

type ActorError struct {
	Op   string
	Err  error
	Code ErrorCode
}

ActorError contains detailed information about an actor error.

func NewError added in v0.4.0

func NewError(op string, err error, code ErrorCode) *ActorError

NewError creates a new actor error.

func (*ActorError) Error added in v0.4.0

func (e *ActorError) Error() string

Error implements the error interface.

func (*ActorError) Unwrap added in v0.4.0

func (e *ActorError) Unwrap() error

Unwrap implements error unwrapping.

type Config added in v0.5.0

type Config struct {
	// Context defines the lifetime of the Actor. If nil,
	// context.Background() will be used.
	Context context.Context

	// QueueCap defines the capacity of the action queue.
	// Must be positive, default is 256.
	QueueCap int

	// Recoverer is called when a panic occurs during action
	// execution. If nil, a default recoverer will be used
	// that wraps the panic value in an error.
	Recoverer Recoverer

	// Finalizer is called when the Actor stops. It receives
	// any error that caused the stop and can transform it.
	// If nil, a default finalizer will be used that returns
	// the error unchanged.
	Finalizer Finalizer

	// ActionTimeout defines a default timeout for all actions.
	// If set to 0 (default), no timeout is applied.
	// Can be overridden per action using DoSyncTimeout or DoAsyncTimeout.
	ActionTimeout time.Duration
}

Config contains all configuration options for an Actor.

func DefaultConfig added in v0.5.0

func DefaultConfig() Config

DefaultConfig returns a Config with default values.

func (*Config) Validate added in v0.5.0

func (c *Config) Validate() error

Validate checks if the configuration is valid and sets default values where needed.

type ErrorCode added in v0.4.0

type ErrorCode int

ErrorCode defines the type of error that occurred.

const (
	// ErrNone signals no error.
	ErrNone ErrorCode = iota
	// ErrShutdown signals that the actor is shutting down.
	ErrShutdown
	// ErrTimeout signals a timeout during operation.
	ErrTimeout
	// ErrCanceled signals that the operation was canceled.
	ErrCanceled
	// ErrPanic signals that a panic occurred during action execution.
	ErrPanic
	// ErrInvalid signals invalid parameters or state.
	ErrInvalid
)

func (ErrorCode) String added in v0.4.0

func (ec ErrorCode) String() string

String implements the Stringer interface.

type Finalizer

type Finalizer func(err error) error

Finalizer defines the signature of a function for finalizing the work of an Actor. The error is the one returned by the Actor.

type QueueStatus added in v0.5.0

type QueueStatus struct {
	Length   int  // Current number of queued requests
	Capacity int  // Maximum queue capacity
	IsFull   bool // Whether queue is at capacity
}

Actor introduces the actor model, where calls are executed sequentially in a backend goroutine. QueueStatus provides information about the actor's request queue

type Recoverer added in v0.3.0

type Recoverer func(reason any) error

Recoverer defines the signature of a function for recovering from a panic during executing an action. The reason is the panic value. The function should return the error to be returned by the Actor. If the error is nil, the Actor will continue to work.

type Result added in v0.4.0

type Result[T any] struct {
	// contains filtered or unexported fields
}

Result encapsulates both a value and a potential error.

func NewResult added in v0.4.0

func NewResult[T any](value T, err error) Result[T]

NewResult creates a new Result instance.

func (Result[T]) Err added in v0.4.0

func (r Result[T]) Err() error

Err returns any error that occurred.

func (Result[T]) Ok added in v0.4.0

func (r Result[T]) Ok() bool

Ok returns true if there is no error.

func (Result[T]) Value added in v0.4.0

func (r Result[T]) Value() T

Value returns the encapsulated value.

Jump to

Keyboard shortcuts

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