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 multipleGoroutinesat 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/gormanTo 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
Unlistenmethod.
For more usage examples, check the examples directory.
Gorman is released under the MIT License.