Thespian is a library supporting use of the actor model in Go code.

Thespian

Thespian is a library supporting use of the actor model in Go code.

NOTE: This is a work in progress and should not (yet? ever?) be used in real code.

Introduction

Briefly, the actor model divides an application into independently-executing entities (actors) that respond to messages. In response to a message, an actor may

  • send messages to other actors
  • create new actors
  • modify its private state to change the way it will react to subsequent messages

Notably, actors may not share data with other actors. All communication occurs by message-passing.

Actors and Mailboxes

A Thespian actor has

  • an instance of a private struct containing the actor's data:
  • mailboxes where incoming messages are received; and
  • handleXxx methods on the private type to respond to messages from each mailbox.

The library runs each actor in a dedicated Goroutine, and handles startup, shutdown, health monitoring, and other administrative details.

Mailboxes are a generalization of Go channels, and can provide:

  • simple message transfer between agents; and
  • time-related messages, such as a message every 15 seconds. Future expansions might include
  • Complex message transfer with improved performance characteristics (such as memory re-use or batching multiple messages into one);
  • RPC message-passing, where the sender of the request message blocks waiting for a response message; and
  • Network listeners, where a new connection or data on an existing socket results in a message.

Code Generation and Usage

This library implements actors by generating Go code based on a specification (thespian.yml). Code generation provides typesafe, ergonomic access and avoids the performance overhead of vtable dispatch for interfaces.

The specification file results in code generated in the same directory. It is typically invoked from a go.gen in the same directory. For example:

# go.gen
//go:generate go run github.com/djmitche/thespian/cmd/thespian generate
# thespian.yml
actors:
  OrderTracker:
    mailboxes:
      newOrder:
        kind: simple
        message-type: "Order"
        type: Order
      orderComplete:
        kind: simple
        message-type: "Order"
        type: Order

mailboxes:
  Order:
    kind: simple
    message-type: PurchaseOrder

Runtime

Actors run in the context of a Runtime, which tracks running actors and handles health-monitoring, supervision, and other oversight responsibilities.

Create a new Runtime with thespian.NewRuntime().

Actors

The actors property of the specification file describes the actor types that will be generated. Each has a set of named mailboxes for that actor type. Each mailbox specifies a kind and some kind-specific values. These are described in the next section.

In addition to the specification in thespian.yml, you must supply a "private type" for the actor. This type must begin by embedding the base type, and can contain any additional private data for the actor. The type must be private and access to an instance is limited to the agent it represents. As such, no synchronization primitives (such as sync.Mutex) are required.

The private type must implement a handleMailboxName method for each mailbox. Continuing the example above:

type orderTracker struct {
    orderTrackerBase

    openOrders map[OrderID]Order
    closedOrders map[OrderID]Order
}

func (ot *orderTracker) handleNewOrder(msg Order) {
    // ...
}

func (ot *orderTracker) handleOrderComplete(msg Order) {
    // ...
}

The generated code contains several struct types, prefixed with the base name given in the specification. For the "OrderTracker" type in the example, these are

  • orderTrackerBase - a base type that should be embedded in the private type, as above.
  • OrderTrackerBuilder - a builder for new actor instances
  • OrderTrackerRx - a struct to handle receiving messages from mailboxes (private to the actor)
  • OrderTrackerTx - a struct to handle sending messages to mailboxes (available to other actors)

Base Type

The ...Base type provides default method implementations:

  • handleStart - called on actor start
  • handleStop - called on clean stop of an actor
  • handleSuperEvernt - called for supervisory events

as well as fields:

  • rx - pointer to the Rx instance for this actor, used to adjust mailbox behavior
  • tx - pointer to the Tx instance for this actor, used to send messages to itself
  • rt - pointer to the thespian.Runtime in which this actor is executing

Builder Type

The Builder type is used to build a new actor. It contains an embedded private struct and a private field for each mailbox. The embedded private struct can be used to set initial values for the actor, and the mailbox fields can be used to configure mailboxes before startup. For example, a mailbox can be configured to be disabled at startup.

You should wrap the builder with one or more constructor functions, returning the ...Tx type, such as

func NewOrderTracker(rt *thespian.Runtime) *OrderTrackerTx {
    return OrderTrackerBuilder{
        orderTracker: {
            openOrders: make(map[OrderID]Order),
            closedOrders: make(map[OrderID]Order),
        },
        orderComplete: OrderMailbox {
            Disabled: true, // orderComplete mailbox will begin in a disabled state
        }
    }.spawn(rt)
}

Rx Type

The Rx type is the actor's interface to its mailboxes. Most mailboxes allow some kind of runtime configuration. For example, simple mailboxes can be enabled or disabled. The Rx type has a field for each mailbox, of the mailbox's Rx type.

For example:

func (ot *orderTracker) handleNewOrder(msg Order) {
    // now that we have an order, allow order completion messages
    ot.rx.orderComplete.Disabled = false
}

Tx Type

The Tx type is the public interface for an actor. It contains only one public field (ID), and implements a method for each mailbox to which messages can be sent.

For example:

ot := NewOrderTracker(rt)
ot.NewOrder(Order{ .. })

An instance of the Tx type may be passed around to any actor that wishes to send messages the actor.

The Tx type also contains a Stop() message which requests that the actor stop on its next iteration.

Mailboxes

Mailboxes are generated from elements in the mailboxes property of thespian.yml. The library also provides a few pre-generated mailbox implementations for common types and purposes.

The library defines several "kinds" of mailboxes, each described below. Most define three types, each with suffixes of the base type name. The Mailbox type defines the mailbox, and when an actor is spawned that Mailbox is split into an Rx and Tx instance. From the example above, these would be

  • OrderMailbox
  • OrderRx
  • OrderTx

Simple Mailboxes

Simple mailboxes simply wrap a typed Go channel. They are defined like this in the specification file:

mailboxes:
  Order:
    kind: simple
    message-type: PurchaseOrder

Where message-type is the type of the messages carried by the channel. At the moment, this type must be defined in the same Go package.

Simple mailboxes can be used in actors as follows:

actors:
  SomeActor:
    mailboxes:
      mailboxName:
        kind: simple
        message-type: "Order"
        import: my.package/path/to/mailboxes
        type: Order

Here, message-type must match the message type used in the mailbox specification, and type must match the base name of the mailbox type in the package identified by import. The import property may be omitted if it is the same as the package in which the actor is defined.

The Mailbox type of a simple mailbox has a C field giving the channel that will carry the messages. When building an actor, setting this field to a channel used by another actor instances will cause the actors to both read from the same channel, with the result that any message sent will reach only one of the waiting actors. The default channel size is 10, but this can be overridden when building an actor by creating a channel of the desired size.

The Mailbox type also has a Disabled property. Setting this to true will cause the Mailbox to start in the disabled state, meaning that it will not receive messages. The default is to begin receiving messages at startup.

The Rx type has a Disabled property as well, that can be manipulated from the actor implementation. In the example above, the OrderCompleted mailbox is enabled only after an order has been created.

Ticker Mailboxes

The ticker kind generates a mailbox that embeds a time.Ticker. There are no Mailbox or Tx types for this mailbox.

When the actor starts, the ticker is disabled. The ticker can be started with rx. .Reset(dur) , and stopped with rx. .Stop() . On each tick, the handleMailboxName(t time.Time) method will be called.

Supervision

(TBD)

An actor may call rx.supervise(someID) to begin "supervising" another actor. The rx.unsupervise(someID) method does the reverse.

A supervising actor receives calls to handleSuperEvent when the state of the supervised actor changes. The supported event types are:

  • thespian.UnhealthyActor - produced when a healthy actor becomes unhealthy
  • thespian.HealthyActor - produced when an unhealthy actor becomes healthy
  • thespian.StoppedActor - produced when the actor stops (whether cleanly or by panic)

The runtime monitors each actor to ensure that it is waiting for messages at least once per second. When this check fails (such as when the actor is deadlocked, or spends too much time in a handle method), any supervising actors are notified.

Caveats

Thespian does not guarantee the order in which messages are delivered between mailboxes. In the "Orders" example above, it is possible for an OrderCompleted message to be delivered before the NewOrder message that created the corresponding order.

Owner
Similar Resources

Command line tool to generate idiomatic Go code for SQL databases supporting PostgreSQL, MySQL, SQLite, Oracle, and Microsoft SQL Server

About xo xo is a command-line tool to generate Go code based on a database schema or a custom query. xo works by using database metadata and SQL intro

Jan 8, 2023

Graphic library supporting various displays

eve Package eve provides interface to FTDI/BRTCHIP Embedded Video Engine display controllers (FT80x, FT81x, BT1x). font Package font provides a simple

Dec 26, 2022

Use Consul to do service discovery, use gRPC +kafka to do message produce and consume. Use redis to store result.

Use  Consul to do service discovery, use gRPC +kafka to do message produce and consume. Use redis to store result.

目录 gRPC/consul/kafka简介 gRPC+kafka的Demo gRPC+kafka整体示意图 限流器 基于redis计数器生成唯一ID kafka生产消费 kafka生产消费示意图 本文kafka生产消费过程 基于pprof的性能分析Demo 使用pprof统计CPU/HEAP数据的

Jul 9, 2022

Several functional programming supporting in golang

A golang library that makes operations on slice easilier What can I do? slice process Map Filter Sort Reverse map process Keys Values output (starting

Jun 27, 2022

A Go package for sending and receiving ethernet frames. Currently supporting Linux, Freebsd, and OS X.

ether ether is a go package for sending and receiving ethernet frames. Currently supported platform: BPF based OS X FreeBSD AF_PACKET based Linux Docu

Sep 27, 2022

A STOMP Client package for go developers, supporting all STOMP specification levels.

stompngo - A STOMP 1.0, 1.1 and 1.2 Client Package Features Full support of STOMP protocols: Protocol Level 1.0 Protocol Level 1.1 Protocol Level 1.2

Oct 19, 2022

Sparse matrix formats for linear algebra supporting scientific and machine learning applications

Sparse matrix formats Implementations of selected sparse matrix formats for linear algebra supporting scientific and machine learning applications. Co

Dec 12, 2022

Sparse matrix formats for linear algebra supporting scientific and machine learning applications

Sparse matrix formats Implementations of selected sparse matrix formats for linear algebra supporting scientific and machine learning applications. Co

Jan 8, 2023

A faster, simpler way to drive browsers supporting the Chrome DevTools Protocol.

About chromedp Package chromedp is a faster, simpler way to drive browsers supporting the Chrome DevTools Protocol in Go without external dependencies

Jan 4, 2023

Supporting your devops by shortening your strings using common abbreviations and clever guesswork

abbreviate Shorten your strings using common abbreviations. Supported by Tidelift Motivation This tool comes out of a frustration of the name of resou

Dec 14, 2022

A MCBE Proxy supporting fast transfer and much more!

A MCBE Proxy supporting fast transfer and much more!

Downloads Pipelines Here you can find all the build please select the latest and click Artifacts

Oct 17, 2022

cTRL is a server for remote execution of pending tasks and commands in real time, supporting a queue with continuous thread limiting and throttling.

Документация на русском: https://github.com/eltaline/ctrl/blob/master/README-RUS.md cTRL is a server written in Go language that uses a modified versi

Mar 3, 2022

This slide deck and supporting material is part of the Introduction to Go training course by Dave Cheney

This slide deck and supporting material is part of the Introduction to Go training course by Dave Cheney.

Nov 14, 2022

A faster, simpler way to drive browsers supporting the Chrome DevTools Protocol.

About chromedp Package chromedp is a faster, simpler way to drive browsers supporting the Chrome DevTools Protocol in Go without external dependencies

Dec 28, 2022

A load balancer supporting multiple LB strategies written in Go

A load balancer supporting multiple LB strategies written in Go

farely A load balancer supporting multiple LB strategies written in Go. Goal The goal of this project is purley educational, I started it as a brainst

Dec 21, 2022

Oogway is a simple web server with dynamic content generation and extendability in mind supporting a Git based workflow.

Oogway Oogway is a simple web server with dynamic content generation and extendability in mind supporting a Git based workflow. It's somewhere in betw

Nov 9, 2022

Kazaam was created with the goal of supporting easy and fast transformations of JSON data with Golang

kazaam Description Kazaam was created with the goal of supporting easy and fast transformations of JSON data with Golang. This functionality provides

Sep 17, 2021

🤼‍♂️ a simple FIFO matchmaker supporting scoring

Matchmaker This package is a simple FIFO matchmaker that supports player rank & latency (as tags). The rank & latency tags help you to group the playe

Oct 4, 2022
Goldorak GO is a mini framework for the Go programming language. (unfinished dead code)

Goldorak Go =========== > Goldorak GO ! Rétrolaser en action > Goldorak GO !! Va accomplir ta mission > Dans l'infini > Des galaxies > Poursuis ta lu

Apr 29, 2021
Flamingo Framework and Core Library. Flamingo is a go based framework for pluggable web projects. It is used to build scalable and maintainable (web)applications.
Flamingo Framework and Core Library. Flamingo is a go based framework for pluggable web projects. It is used to build scalable and maintainable (web)applications.

Flamingo Framework Flamingo is a web framework based on Go. It is designed to build pluggable and maintainable web projects. It is production ready, f

Jan 5, 2023
Simple HTTP and REST client library for Go

Resty Simple HTTP and REST client library for Go (inspired by Ruby rest-client) Features section describes in detail about Resty capabilities Resty Co

Jan 9, 2023
go-actor is a lightweight message framework using actor model

go-actor go-actor is a lightweight message framework using actor model 初衷 想能在代码逻辑上方便的写无锁的同步rpc调用代码,同时又不会阻塞住其他服务对这个Actor的调用 一个Actor可以有多种身份,想能比较方便的分类管理A

Oct 21, 2022
If I were a malicious actor, how would I sneak my code in?

go-error-hijack-poc This repo demonstrates a hypothetical use of sentinel errors and horizontally off-screen code as attack vectors. How to Run Run th

Jan 15, 2022
CRUDist Model Driven Web Development. Automagically generate CRUD APIs from your model.

CRUDist - Model Driven API Development Automagicaly create CRUD APIs for your gorm models. Example Model definition type BaseModel struct { ID

Nov 15, 2021
Transmo - Transform Model into another model based on struct for Go (Golang).

Transmo Transmo is a Go library for transform model into another model base on struct. This library detect your field name to copy that into another m

Jan 7, 2022
An actor framework for Go

gosiris is an actor framework for Golang. Features Manage a hierarchy of actors (each actor has its own: state, behavior, mailbox, child actors) Deplo

Dec 28, 2022
Infrastructure supporting the use of Go in Microsoft

Microsoft Go Infrastructure This repository contains libraries and utilities that Microsoft uses to: Build Go inside Microsoft infrastructure using up

Dec 15, 2022
Golang JSON decoder supporting case-sensitive, number-preserving, and strict decoding use cases

Golang JSON decoder supporting case-sensitive, number-preserving, and strict decoding use cases

Dec 9, 2022