Gorman is a lightweight Go package for managing and monitoring the execution of goroutines.
It provides two core concepts:
Goroutine
: Struct wrapping a goroutine and allowing to control its execution using Start/Stop semantics.Manager
: Allows controlling multipleGoroutines
at once and managing their lifecycle as a group.
The Manager
can be helpful to create Goroutine supervisors with a HTTP or CLI implementation
to start and stop specific Goroutines.
To install Gorman, use go get:
go get -u github.com/morebec/gorman
To use Gorman, you first need to import it in your Go project:
import "github.com/morebec/gorman"
Next, you can create a new instance of a Manager:
man := gorman.NewManager(gorman.Options{
Logger: slog.New(tint.Options{
Level: slog.LevelDebug,
TimeFormat: time.TimeOnly,
}.NewHandler(os.Stdout)),
})
You can then register a new Goroutine with the manager:
man.Add("MyGoroutine", func(ctx context.Context) error {
// Goroutine logic goes here
select {
case <-ctx.Done():
return nil
}
}, gorman.NeverRestart())
The last parameter allows specifying the restart policy of the Goroutine. Out of the box the following Restart Policies are implemented:
NeverRestart()
: Never restarts the Goroutine once it has stopped.AlwaysRestart()
: Always restarts the Goroutine.RestartOnError()
: Restart the Goroutine when it stops with an error.RestartPolicyFunc
: Allows specifying the restart logic using a function.
See the RestartPolicy
interface for more information.
The Run
method, allows running the manager and starting all the goroutines that were added to it:
man.Run(context.Background())
This method will run until the context is canceled, or the Shutdown
method is called.
To stop a running Goroutine, you can call Stop
:
err := manager.Stop("MyGoroutine")
if err != nil {
// handle error
}
Note: For goroutines to be stoppable they should correctly listen to the ctx.Done() channel. Go routines will also stop whenever they return.
It is possible to start a goroutine that was previously stopped using the Start
method:
err := man.Start(context.Background(), "mygoroutine")
The manager exposes the Status method which returns a slice of GoroutineState
which represents the current state of Goroutines.
Goroutines are the building blocks of Gorman and wrap the execution of a go routine to allow start/stop semantics. They can be used independently of the manager to control specific goroutines in isolation.
g := gorman.NewGoroutine("name", func (ctx context.Context) error {
// Perform work here.
})
g.Start(context.Background())
The Stop
method will cancel the goroutine's context and will wait for it
to be stopped.
err := g.Stop()
Alternatively a goroutine can be stopped through its context.
ctx, cancel := context.WithCancel(context.Background())
g.Start(ctx)
cancel()
Goroutines have an internal broadcasting system that allows subscribers to listen to Goroutine events
such as GoroutineStartedEvent
and GoroutineEndedEvent
.
Here's an example:
g := gorman.NewGoroutine("mygoroutine", func(ctx context.Context) error {
// do something
return nil
})
eventChan := g.Listen()
g.Start(context.Background())
for event := range eventChan {
switch event.(type) {
case gorman.GoroutineStartedEvent:
fmt.Printf("Goroutine %s started\n", g.State.Name)
case gorman.GoroutineStoppedEvent:
e := event.(GoroutineStoppedEvent)
if e.Error != nil {
fmt.Printf("Goroutine %s stopped with error: %s\n", event.Name, event.Error.Error())
} else {
fmt.Printf("Goroutine %s stopped\n", event.Name)
}
}
}
g.Unlisten(eventChan)
This mechanism can be useful to react to a goroutine's execution. For instance
the Manager
uses this mechanism to monitor the lifecycle of the Goroutines.
Note: Every call to the Listen() method will return a new channel. When done with using the channel, it should be released using the
Unlisten
method.
For more usage examples, check the examples
directory.
Gorman is released under the MIT License.