Browse Source

initial

master
Chakib Benziane 1 year ago
commit
70c37ac411
2 changed files with 206 additions and 0 deletions
  1. 98
    0
      README.md
  2. 108
    0
      manager.go

+ 98
- 0
README.md View File

@@ -0,0 +1,98 @@
1
+# gum
2
+
3
+Go Unit Manager is a simple Goroutine unit manager for GoLang.
4
+
5
+
6
+Features:
7
+
8
+- Scheduling of multiple goroutines.
9
+- Subscribe to `os.Signal` events.
10
+- Gracefull shutdown of units
11
+
12
+
13
+## Overview
14
+
15
+A unit is a type that implements `WorkUnit` interface. The `Spawn()` method
16
+of registered units are run in goroutines. 
17
+
18
+The `Manager` handles communication and synchronized shutdown procedure.
19
+
20
+
21
+## Usage
22
+
23
+1. Create a unit manager
24
+2. Implement the `WorkUnit` on your goroutines
25
+3. Add units to the manager
26
+4. Start the manager and wait on it's `Quit` channel
27
+
28
+```golang
29
+import (
30
+    "os"
31
+    "log"
32
+    "time"
33
+    "git.sp4ke.com/sp4ke/gum"
34
+)
35
+
36
+type Worker struct{}
37
+
38
+// Example loop, it will be spwaned in a goroutine
39
+func (w *Worker) Spawn(um UnitManager) {
40
+	ticker := time.NewTicker(time.Second)
41
+
42
+    // Worker's loop
43
+	for {
44
+		select {
45
+		case <-ticker.C:
46
+			log.Println("tick")
47
+
48
+        // Read from channel if this worker unit should stop
49
+		case <-um.ShouldStop():
50
+
51
+            // Shutdown work for current unit
52
+			w.Shutdown()
53
+
54
+            // Notify manager that this unit is done.
55
+			um.Done()
56
+		}
57
+	}
58
+}
59
+
60
+func (w *Worker) Shutdown() {
61
+    // Do shutdown procedure for worker
62
+    return
63
+}
64
+
65
+func NewWorker() *Worker {
66
+    return &Worker{}
67
+}
68
+
69
+func main() {
70
+    // Create a unit manager
71
+    manager := gum.NewManager()
72
+
73
+    // Subscribe to SIGINT
74
+    manager.SubscribeTo(os.Interrupt)
75
+
76
+    // NewWorker returns a type implementing WorkUnit interface unit :=
77
+    worker := NewWorker()
78
+
79
+    // Register the unit with the manager
80
+    manager.AddUnit(worker)
81
+
82
+    // Start the manager
83
+    go manager.Start()
84
+
85
+
86
+    // Wait for all units to shutdown gracefully through their `Shutdown` method
87
+    <-manager.Quit
88
+}
89
+```
90
+
91
+## Issues and Comments
92
+The github repo is just a mirror.
93
+
94
+For any question or issues use the repo hosted at
95
+https://git.sp4ke.com/sp4ke/gum. 
96
+
97
+
98
+

+ 108
- 0
manager.go View File

@@ -0,0 +1,108 @@
1
+package gum
2
+
3
+import (
4
+	"log"
5
+	"os"
6
+	"os/signal"
7
+	"reflect"
8
+	"strings"
9
+)
10
+
11
+type WorkUnit interface {
12
+	Spawn(UnitManager)
13
+	Shutdown()
14
+}
15
+
16
+type UnitManager interface {
17
+	ShouldStop() <-chan bool
18
+	Done()
19
+}
20
+
21
+type WorkUnitManager struct {
22
+	stop       chan bool
23
+	workerQuit chan bool
24
+	unit       WorkUnit
25
+}
26
+
27
+func (w *WorkUnitManager) ShouldStop() <-chan bool {
28
+	return w.stop
29
+}
30
+
31
+func (w *WorkUnitManager) Done() {
32
+	w.workerQuit <- true
33
+}
34
+
35
+type Manager struct {
36
+	signal chan os.Signal
37
+
38
+	workers map[string]*WorkUnitManager
39
+
40
+	Quit chan bool
41
+}
42
+
43
+func (m *Manager) Start() {
44
+	log.Println("Starting manager ...")
45
+
46
+	for unitName, w := range m.workers {
47
+		log.Printf("Starting <%s>\n", unitName)
48
+		go w.unit.Spawn(w)
49
+	}
50
+
51
+	for {
52
+		select {
53
+		case sig := <-m.signal:
54
+			if sig != os.Interrupt {
55
+				break
56
+			}
57
+
58
+			log.Println("shutting event received ... ")
59
+
60
+			// send shutdown event to all worker units
61
+			for name, w := range m.workers {
62
+				log.Printf("shuting down <%s>\n", name)
63
+				w.stop <- true
64
+			}
65
+
66
+			// Wait for all units to quit
67
+			for name, w := range m.workers {
68
+				<-w.workerQuit
69
+				log.Printf("<%s> down", name)
70
+			}
71
+
72
+			// All workers have shutdown
73
+			log.Println("All workers have shutdown, shutting down manager ...")
74
+
75
+			m.Quit <- true
76
+
77
+		}
78
+	}
79
+}
80
+
81
+func (m *Manager) SubscribeTo(sig os.Signal) {
82
+	signal.Notify(m.signal, sig)
83
+}
84
+
85
+func (m *Manager) AddUnit(unit WorkUnit) {
86
+
87
+	workUnitManager := &WorkUnitManager{
88
+		workerQuit: make(chan bool, 1),
89
+		stop:       make(chan bool, 1),
90
+		unit:       unit,
91
+	}
92
+
93
+	unitType := reflect.TypeOf(unit)
94
+	unitName := strings.Split(unitType.String(), ".")[1]
95
+
96
+	log.Println("Adding unit ", unitName)
97
+
98
+	m.workers[unitName] = workUnitManager
99
+	log.Println(m.workers)
100
+}
101
+
102
+func NewManager() *Manager {
103
+	return &Manager{
104
+		signal:  make(chan os.Signal, 1),
105
+		Quit:    make(chan bool),
106
+		workers: make(map[string]*WorkUnitManager),
107
+	}
108
+}

Loading…
Cancel
Save