initial
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…
Reference in New Issue