-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprocessManager.go
More file actions
132 lines (108 loc) · 2.54 KB
/
Copy pathprocessManager.go
File metadata and controls
132 lines (108 loc) · 2.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"os/signal"
"strings"
"syscall"
"time"
"sync"
)
const DEFAULT_NUMBER_OF_WORKERS int = 1
const DEFAULT_CMD string = "sh"
const PARAM_ARGS_FLAG_NAME string = "args"
const PARAM_COUNT_OF_WORKERS_FLAG_NAME string = "countOfWorkers"
const PARAM_CMD_FLAG_NAME string = "cmd"
type arguments []string
func (a *arguments) String() string {
return strings.Join(*a, ", ")
}
func (a *arguments) Set(value string) error {
*a = append(*a, value)
return nil
}
var countOfWorkers int
var cmdString string
var args arguments
var killWaitGroup sync.WaitGroup
func startCmd(killWorkersChan chan bool) error {
command := exec.Command(cmdString, args...)
successChan := make(chan bool)
killWaitGroup.Add(1)
command.Start()
go func() {
select {
case <-killWorkersChan:
command.Process.Kill()
case <-successChan:
}
}()
err := command.Wait()
killWaitGroup.Done()
if err != nil {
fmt.Fprintln(os.Stderr, "There was an error running command: ", err)
successChan <- false
return err
}
successChan <- true
return nil
}
func worker(finishChan chan bool, killWorkersChan chan bool) {
if err := startCmd(killWorkersChan); err != nil {
finishChan <- false
} else {
finishChan <- true
}
}
func getErrorDuration(errorsCount int) time.Duration {
pauseCoefficient := errorsCount / countOfWorkers
return time.Duration(pauseCoefficient * pauseCoefficient) * time.Second
}
func parseFlags() {
flag.IntVar(&countOfWorkers, PARAM_COUNT_OF_WORKERS_FLAG_NAME, DEFAULT_NUMBER_OF_WORKERS, "Count of workers")
flag.StringVar(&cmdString, PARAM_CMD_FLAG_NAME, DEFAULT_CMD, "Worker command")
flag.Var(&args, PARAM_ARGS_FLAG_NAME, "Worker command arguments")
flag.Parse()
if flag.NFlag() == 0 {
flag.Usage()
os.Exit(1)
}
}
func catchKillSignal() (chan bool) {
killWorkersChan := make(chan bool)
osKillSignalChan := make(chan os.Signal, 1)
signal.Notify(osKillSignalChan, os.Interrupt, os.Kill, syscall.SIGTERM)
go func() {
<-osKillSignalChan
close(killWorkersChan)
}()
return killWorkersChan
}
func main() {
parseFlags()
workerEndChan := make(chan bool)
workersCount := 0
errorsCount := 0
killWorkersChan := catchKillSignal()
for {
select {
case <-killWorkersChan:
killWaitGroup.Wait()
os.Exit(1)
case <-time.After(getErrorDuration(errorsCount)):
if workersCount < countOfWorkers {
workersCount++
go worker(workerEndChan, killWorkersChan)
}
case success := <-workerEndChan:
if !success {
errorsCount++
} else {
errorsCount = 0
}
workersCount--
}
}
}