genserver

package module
v1.3.1 Latest Latest
Warning

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

Go to latest
Published: Apr 21, 2021 License: Apache-2.0 Imports: 7 Imported by: 1

README

genserver Build Go Report Card

Minimal actor model component GenServer inspired by this awesome talk by Bryan Boreham who complained about not having a library. So here you go Bryan 😀.

  • Keep concurrency in check with GenServers
  • Have a minimal library to keep things similiar
  • Builtin deadlock detection

Basic Example:

type Counter struct {
	gen    *genserver.GenServer
	number int64
}

func StartCounter() *Counter {
	gen := genserver.New("Counter")
	return &Counter{gen: gen, number: 0}
}

func (counter *Counter) Incr() (ret uint64) {
	counter.gen.Call(func() {
		counter.number++
        ret = counter.number
	})
    return
}

Deadlock detection

The library will detect when a GenServer is beeing waited for more than 30 seconds to detect Deadlocks. This can be disabled but helps in default mode to detect deadlocks such as those Bryan showed in his presentation:

Deadlock

Running the example in examples/deadlock/deadlock.go you will get a WARNING like this:

GenServer WARNING timeout in Connection:19
GenServer stuck in
goroutine 19 [runnable]:
runtime.Stack(0xc00036c000, 0xf4240, 0xf4240, 0xc00036c001, 0x1)
        /usr/lib/go-1.15/src/runtime/mprof.go:803 +0x12a
github.com/dominicletz/genserver.(*GenServer).Call(0xc0000c4140, 0xc000096240)
        /home/dominicletz/projects/genserver/genserver.go:111 +0x1e9
main.(*Peer).ConnEstablished(0xc000096220)
        /home/dominicletz/projects/genserver/examples/deadlock/deadlock.go:58 +0x5f
main.(*Connection).handleSetEstablished(0xc0000961f0)
        /home/dominicletz/projects/genserver/examples/deadlock/deadlock.go:45 +0x2f
main.(*Connection).queryLoop(0xc0000961f0)
        /home/dominicletz/projects/genserver/examples/deadlock/deadlock.go:41 +0x2b
main.(*Connection).SendGossipMessage.func1()
        /home/dominicletz/projects/genserver/examples/deadlock/deadlock.go:36 +0x2a
github.com/dominicletz/genserver.(*GenServer).Call.func1()
        /home/dominicletz/projects/genserver/genserver.go:105 +0x2f
github.com/dominicletz/genserver.(*GenServer).loop(0xc0000c4050)
        /home/dominicletz/projects/genserver/genserver.go:70 +0x5b
created by github.com/dominicletz/genserver.New
        /home/dominicletz/projects/genserver/genserver.go:52 +0xc5

Building the examples

> go build -tags example  ./examples/*

Note on runtime.GetGoID()

By default the GenServer module is using https://github.com/petermattis/goid to get the goid for two uses:

  1. To make Self-calls safe, if the callers goid == the callee goid they can pass, preventing deadlocks by sending a message to one-self.
  2. Deadlock detection, to print the stacktrace of the correct goroutine If you don't have runtime.GetGoID() yet run the attached script:

If you're running on an arm32 or other seldom architecture petermattis/goid will fallback to a very slow method of getting the goid. In that case you can use the included script to inject a fast native goid accessor into your runtime:

> ./patch_runtime.sh

Then compile your app with the additional tag patch_runtime. E.g. to test if this works you can compile the examples with:

> go build -tags patch_runtime,example  ./examples/*

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultDeadlockCallback

func DefaultDeadlockCallback(server *GenServer, trace string)

DefaultDeadlockCallback is the default handler for deadlock detection

Types

type GenServer

type GenServer struct {
	Terminate        func()
	DeadlockTimeout  time.Duration
	DeadlockCallback func(*GenServer, string)
	// contains filtered or unexported fields
}

GenServer structure

func New

func New(label string) *GenServer

New creates a new genserver Assign the Terminate function to define a callback just before the worker stops

func (*GenServer) Call

func (server *GenServer) Call(fun func()) error

Call executes a synchronous call operation

func (*GenServer) Call2 added in v1.2.0

func (server *GenServer) Call2(fun func(*Reply) bool)

Call executes a synchronous call operation

func (*GenServer) Call2Timeout added in v1.2.0

func (server *GenServer) Call2Timeout(fun func(*Reply) bool, timeout time.Duration) error

Call executes a synchronous call operation

func (*GenServer) CallTimeout added in v1.1.0

func (server *GenServer) CallTimeout(fun func(), timeout time.Duration) error

Call executes a synchronous call operation

func (*GenServer) Cast

func (server *GenServer) Cast(fun func()) error

Cast executes an asynchrounous operation

func (*GenServer) Name

func (server *GenServer) Name() string

Name returns the label and goid of this GenServer

func (*GenServer) Shutdown

func (server *GenServer) Shutdown(lingerTime time.Duration)

Shutdown sends a shutdown signal to the server. It will still operate for lingerTime before stopping

type Reply added in v1.2.0

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

func (*Reply) ReRun added in v1.2.0

func (reply *Reply) ReRun()

Jump to

Keyboard shortcuts

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