Home

Awesome

go-actor

test lint coverage Go Report Card GoDoc Release

goactor-cover

go-actor is tiny library for writing concurrent programs in Go using actor model.

Motivation

Intention of go-actor is to bring actor model closer to Go developers and to provide design pattern needed to build scalable and high performing concurrent programs.

Without re-usable design principles codebase of complex system can become hard to maintain. Codebase written using Golang can highly benefit from design principles based on actor model as goroutines and channels naturally translate to actors and mailboxes.

Advantage

Abstractions

go-actor's base abstraction layer only has three interfaces:

Examples

Dive into examples to see go-actor in action.

// This example will demonstrate how to create actors for producer-consumer use case.
// Producer will create incremented number on every 1 second interval and
// consumer will print whatever number it receives.
func main() {
	mbx := actor.NewMailbox[int]()

	// Produce and consume workers are created with same mailbox
	// so that produce worker can send messages directly to consume worker
	p := actor.New(&producerWorker{mailbox: mbx})
	c1 := actor.New(&consumerWorker{mailbox: mbx, id: 1})

	// Note: Example creates two consumers for the sake of demonstration
	// since having one or more consumers will produce the same result. 
	// Message on stdout will be written by first consumer that reads from mailbox.
	c2 := actor.New(&consumerWorker{mailbox: mbx, id: 2})

	// Combine all actors to singe actor so we can start and stop all at once
	a := actor.Combine(mbx, p, c1, c2).Build()
	a.Start()
	defer a.Stop()
	
	// Stdout output:
	// consumed 1      (worker 1)
	// consumed 2      (worker 2)
	// consumed 3      (worker 1)
	// consumed 4      (worker 2)
	// ...

	select {}
}

// producerWorker will produce incremented number on 1 second interval
type producerWorker struct {
	mailbox actor.MailboxSender[int]
	num  int
}

func (w *producerWorker) DoWork(ctx actor.Context) actor.WorkerStatus {
	select {
	case <-ctx.Done():
		return actor.WorkerEnd

	case <-time.After(time.Second):
		w.num++
		w.mailbox.Send(ctx, w.num)

		return actor.WorkerContinue
	}
}

// consumerWorker will consume numbers received on mailbox
type consumerWorker struct {
	mailbox actor.MailboxReceiver[int]
	id  int
}

func (w *consumerWorker) DoWork(ctx actor.Context) actor.WorkerStatus {
	select {
	case <-ctx.Done():
		return actor.WorkerEnd

	case num := <-w.mailbox.ReceiveC():
		fmt.Printf("consumed %d \t(worker %d)\n", num, w.id)

		return actor.WorkerContinue
	}
}

Addons

go-actor is intended to be a tiny library with lean interfaces and basic mechanism providing core building blocks. However, developers may build on top of it and extend it's functionality with user or domain specific addon abstractions. This section lists addon abstractions for go-actor which could be used in addition to it.

Pro tips

To enhance the code quality of projects that heavily rely on the actor model and utilize the go-actor library, it's recommended to adhere to best practices.

Reading about common hurdles, where the most frequent issues are documented, is also advisable.

Design decisions

Design decisions are documented here.

Versioning

The go-actor library adopts a versioning scheme structured as x.y.z.

Initially, the library will utilize the format 0.y.z as it undergoes refinement until it attains a level of stability where fundamental interfaces and core principles no longer necessitate significant alterations. Within this semantic, the y component signifies a version that is not backward-compatible. It is advisable for developers to review the release notes carefully to gain insight into these modifications. Furthermore, the final component, z, denotes releases incorporating changes that are backward-compatible.

Contribution

All contributions are useful, whether it is a simple typo, a more complex change, or just pointing out an issue. We welcome any contribution so feel free to open PR or issue.

Continue reading here.

Happy coding 🌞