commit 70c37ac411ae55e4a0a9b594199b41cab2f8027c Author: Chakib Benziane Date: Fri Dec 7 17:56:14 2018 +0100 initial diff --git a/README.md b/README.md new file mode 100644 index 0000000..e62a0f5 --- /dev/null +++ b/README.md @@ -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. + + + diff --git a/manager.go b/manager.go new file mode 100644 index 0000000..c06021c --- /dev/null +++ b/manager.go @@ -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), + } +}