Browse Source

handle units with same base Type, tests

master
Chakib Benziane 2 years ago
parent
commit
10fd30ba32
3 changed files with 126 additions and 10 deletions
  1. +3
    -1
      README.md
  2. +41
    -9
      manager.go
  3. +82
    -0
      manager_test.go

+ 3
- 1
README.md View File

@ -35,7 +35,7 @@ import (
type Worker struct{}
// Example loop, it will be spwaned in a goroutine
// Example loop, will be spwaned inside a goroutine
func (w *Worker) Spawn(um UnitManager) {
ticker := time.NewTicker(time.Second)
@ -75,9 +75,11 @@ func main() {
// NewWorker returns a type implementing WorkUnit interface unit :=
worker := NewWorker()
worker2 := NewWorker()
// Register the unit with the manager
manager.AddUnit(worker)
manager.AddUnit(worker2)
// Start the manager
go manager.Start()

+ 41
- 9
manager.go View File

@ -5,9 +5,12 @@ import (
"os"
"os/signal"
"reflect"
"strconv"
"strings"
)
var idGen = IdGenerator()
type WorkUnit interface {
Spawn(UnitManager)
Shutdown()
@ -43,7 +46,9 @@ func (w *WorkUnitManager) Panic(err error) {
}
type Manager struct {
signal chan os.Signal
signalIn chan os.Signal
shutdownSigs []os.Signal
workers map[string]*WorkUnitManager
@ -62,8 +67,9 @@ func (m *Manager) Start() {
for {
select {
case sig := <-m.signal:
if sig != os.Interrupt {
case sig := <-m.signalIn:
if !in(m.shutdownSigs, sig) {
break
}
@ -120,7 +126,21 @@ func (m *Manager) Start() {
}
func (m *Manager) ShutdownOn(sig os.Signal) {
signal.Notify(m.signal, sig)
signal.Notify(m.signalIn, sig)
m.shutdownSigs = append(m.shutdownSigs, sig)
}
type IDGenerator func(string) int
func IdGenerator() IDGenerator {
ids := make(map[string]int)
return func(unit string) int {
ret := ids[unit]
ids[unit]++
return ret
}
}
func (m *Manager) AddUnit(unit WorkUnit) {
@ -135,17 +155,29 @@ func (m *Manager) AddUnit(unit WorkUnit) {
unitType := reflect.TypeOf(unit)
unitName := strings.Split(unitType.String(), ".")[1]
unitId := idGen(unitName)
unitName += strconv.Itoa(unitId)
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, 1),
workers: make(map[string]*WorkUnitManager),
panic: make(chan error, 1),
signalIn: make(chan os.Signal, 1),
Quit: make(chan bool, 1),
workers: make(map[string]*WorkUnitManager),
panic: make(chan error, 1),
}
}
// Test if signal is in array
func in(arr []os.Signal, sig os.Signal) bool {
for _, s := range arr {
if s == sig {
return true
}
}
return false
}

+ 82
- 0
manager_test.go View File

@ -0,0 +1,82 @@
package gum
import (
"log"
"os"
"syscall"
"testing"
"time"
)
var WorkerID int
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 DoRunMain(pid chan int, quit chan<- bool) {
pid <- os.Getpid()
// Create a unit manager
manager := NewManager()
// Shutdown all units on SIGINT
manager.ShutdownOn(os.Interrupt)
// NewWorker returns a type implementing WorkUnit interface unit :=
worker1 := NewWorker()
worker2 := NewWorker()
// Register the unit with the manager
manager.AddUnit(worker1)
manager.AddUnit(worker2)
// Start the manager
go manager.Start()
// Wait for all units to shutdown gracefully through their `Shutdown` method
<-manager.Quit
quit <- true
}
func TestRunMain(t *testing.T) {
mainPid := make(chan int, 1)
quit := make(chan bool)
go DoRunMain(mainPid, quit)
time.Sleep(3 * time.Second)
syscall.Kill(<-mainPid, syscall.SIGINT)
<-quit
}

Loading…
Cancel
Save