master
Chakib Benziane 5 years ago
commit 70c37ac411

@ -0,0 +1,98 @@
# gum
Go Unit Manager is a simple Goroutine unit manager for GoLang.
Features:
- Scheduling of multiple goroutines.
- Subscribe to `os.Signal` events.
- Gracefull shutdown of units
## Overview
A unit is a type that implements `WorkUnit` interface. The `Spawn()` method
of registered units are run in goroutines.
The `Manager` handles communication and synchronized shutdown procedure.
## Usage
1. Create a unit manager
2. Implement the `WorkUnit` on your goroutines
3. Add units to the manager
4. Start the manager and wait on it's `Quit` channel
```golang
import (
"os"
"log"
"time"
"git.sp4ke.com/sp4ke/gum"
)
type Worker struct{}
// Example loop, it will be spwaned in a goroutine
func (w *Worker) Spawn(um UnitManager) {
ticker := time.NewTicker(time.Second)
// Worker's loop
for {
select {
case <-ticker.C:
log.Println("tick")
// Read from channel if this worker unit should stop
case <-um.ShouldStop():
// Shutdown work for current unit
w.Shutdown()
// Notify manager that this unit is done.
um.Done()
}
}
}
func (w *Worker) Shutdown() {
// Do shutdown procedure for worker
return
}
func NewWorker() *Worker {
return &Worker{}
}
func main() {
// Create a unit manager
manager := gum.NewManager()
// Subscribe to SIGINT
manager.SubscribeTo(os.Interrupt)
// NewWorker returns a type implementing WorkUnit interface unit :=
worker := NewWorker()
// Register the unit with the manager
manager.AddUnit(worker)
// Start the manager
go manager.Start()
// Wait for all units to shutdown gracefully through their `Shutdown` method
<-manager.Quit
}
```
## Issues and Comments
The github repo is just a mirror.
For any question or issues use the repo hosted at
https://git.sp4ke.com/sp4ke/gum.

@ -0,0 +1,108 @@
package gum
import (
"log"
"os"
"os/signal"
"reflect"
"strings"
)
type WorkUnit interface {
Spawn(UnitManager)
Shutdown()
}
type UnitManager interface {
ShouldStop() <-chan bool
Done()
}
type WorkUnitManager struct {
stop chan bool
workerQuit chan bool
unit WorkUnit
}
func (w *WorkUnitManager) ShouldStop() <-chan bool {
return w.stop
}
func (w *WorkUnitManager) Done() {
w.workerQuit <- true
}
type Manager struct {
signal chan os.Signal
workers map[string]*WorkUnitManager
Quit chan bool
}
func (m *Manager) Start() {
log.Println("Starting manager ...")
for unitName, w := range m.workers {
log.Printf("Starting <%s>\n", unitName)
go w.unit.Spawn(w)
}
for {
select {
case sig := <-m.signal:
if sig != os.Interrupt {
break
}
log.Println("shutting event received ... ")
// send shutdown event to all worker units
for name, w := range m.workers {
log.Printf("shuting down <%s>\n", name)
w.stop <- true
}
// Wait for all units to quit
for name, w := range m.workers {
<-w.workerQuit
log.Printf("<%s> down", name)
}
// All workers have shutdown
log.Println("All workers have shutdown, shutting down manager ...")
m.Quit <- true
}
}
}
func (m *Manager) SubscribeTo(sig os.Signal) {
signal.Notify(m.signal, sig)
}
func (m *Manager) AddUnit(unit WorkUnit) {
workUnitManager := &WorkUnitManager{
workerQuit: make(chan bool, 1),
stop: make(chan bool, 1),
unit: unit,
}
unitType := reflect.TypeOf(unit)
unitName := strings.Split(unitType.String(), ".")[1]
log.Println("Adding unit ", unitName)
m.workers[unitName] = workUnitManager
log.Println(m.workers)
}
func NewManager() *Manager {
return &Manager{
signal: make(chan os.Signal, 1),
Quit: make(chan bool),
workers: make(map[string]*WorkUnitManager),
}
}
Loading…
Cancel
Save