|
@@ -15,12 +15,13 @@ import (
|
|
type ctrlAction uint8
|
|
type ctrlAction uint8
|
|
|
|
|
|
const (
|
|
const (
|
|
- jobStart ctrlAction = iota
|
|
|
|
- jobStop // stop syncing keep the job
|
|
|
|
- jobDisable // disable the job (stops goroutine)
|
|
|
|
- jobRestart // restart syncing
|
|
|
|
- jobPing // ensure the goroutine is alive
|
|
|
|
- jobHalt // worker halts
|
|
|
|
|
|
+ jobStart ctrlAction = iota
|
|
|
|
+ jobStop // stop syncing keep the job
|
|
|
|
+ jobDisable // disable the job (stops goroutine)
|
|
|
|
+ jobRestart // restart syncing
|
|
|
|
+ jobPing // ensure the goroutine is alive
|
|
|
|
+ jobHalt // worker halts
|
|
|
|
+ jobForceStart // ignore concurrent limit
|
|
)
|
|
)
|
|
|
|
|
|
type jobMessage struct {
|
|
type jobMessage struct {
|
|
@@ -211,22 +212,25 @@ func (m *mirrorJob) Run(managerChan chan<- jobMessage, semaphore chan empty) err
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
- runJob := func(kill <-chan empty, jobDone chan<- empty) {
|
|
|
|
|
|
+ runJob := func(kill <-chan empty, jobDone chan<- empty, bypassSemaphore <-chan empty) {
|
|
select {
|
|
select {
|
|
case semaphore <- empty{}:
|
|
case semaphore <- empty{}:
|
|
defer func() { <-semaphore }()
|
|
defer func() { <-semaphore }()
|
|
runJobWrapper(kill, jobDone)
|
|
runJobWrapper(kill, jobDone)
|
|
|
|
+ case <-bypassSemaphore:
|
|
|
|
+ runJobWrapper(kill, jobDone)
|
|
case <-kill:
|
|
case <-kill:
|
|
jobDone <- empty{}
|
|
jobDone <- empty{}
|
|
return
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ bypassSemaphore := make(chan empty, 1)
|
|
for {
|
|
for {
|
|
if m.State() == stateReady {
|
|
if m.State() == stateReady {
|
|
kill := make(chan empty)
|
|
kill := make(chan empty)
|
|
jobDone := make(chan empty)
|
|
jobDone := make(chan empty)
|
|
- go runJob(kill, jobDone)
|
|
|
|
|
|
+ go runJob(kill, jobDone, bypassSemaphore)
|
|
|
|
|
|
_wait_for_job:
|
|
_wait_for_job:
|
|
select {
|
|
select {
|
|
@@ -249,6 +253,12 @@ func (m *mirrorJob) Run(managerChan chan<- jobMessage, semaphore chan empty) err
|
|
<-jobDone
|
|
<-jobDone
|
|
time.Sleep(time.Second) // Restart may fail if the process was not exited yet
|
|
time.Sleep(time.Second) // Restart may fail if the process was not exited yet
|
|
continue
|
|
continue
|
|
|
|
+ case jobForceStart:
|
|
|
|
+ select { //non-blocking
|
|
|
|
+ default:
|
|
|
|
+ case bypassSemaphore <- empty{}:
|
|
|
|
+ }
|
|
|
|
+ fallthrough
|
|
case jobStart:
|
|
case jobStart:
|
|
m.SetState(stateReady)
|
|
m.SetState(stateReady)
|
|
goto _wait_for_job
|
|
goto _wait_for_job
|
|
@@ -272,8 +282,14 @@ func (m *mirrorJob) Run(managerChan chan<- jobMessage, semaphore chan empty) err
|
|
case jobDisable:
|
|
case jobDisable:
|
|
m.SetState(stateDisabled)
|
|
m.SetState(stateDisabled)
|
|
return nil
|
|
return nil
|
|
|
|
+ case jobForceStart:
|
|
|
|
+ select { //non-blocking
|
|
|
|
+ default:
|
|
|
|
+ case bypassSemaphore <- empty{}:
|
|
|
|
+ }
|
|
|
|
+ fallthrough
|
|
case jobRestart:
|
|
case jobRestart:
|
|
- m.SetState(stateReady)
|
|
|
|
|
|
+ fallthrough
|
|
case jobStart:
|
|
case jobStart:
|
|
m.SetState(stateReady)
|
|
m.SetState(stateReady)
|
|
default:
|
|
default:
|