このスケジューラーを作成しましたが、入力時間間隔よりも時間がかかるf
場合にその入力関数を「kill」することができません。f
recurring
それf
がスレッドではなくプロセスである場合、私が探しているのは、ある種の定義済みのハード プリエンプションである可能性があります。
そのf
定義は、私が制御できないものです。これは、バッチ実行中に複数のデータベースからデータを処理する ETL ジョブを表しています。それf
は書かれてgo
おり、正常に動作しますが、実行に時間がかかりすぎる何らかの制御が必要です。
私f
はアトミックであることを知っているので、実行の最後にデータベースを変更するかどうかのどちらかです。したがって、時間がかかりすぎる場合は、「殺す」のが安全であると見なすことができます。
func schedule(f func(), recurring time.Duration) chan struct{} {
ticker := time.NewTicker(recurring)
quit := make(chan struct{})
go func(inFunc func()) {
for {
select {
case <-ticker.C:
fmt.Println("Ticked")
// when "go" is removed, then if "f()" takes
// more than "recurring", then it postpones
// the following executions of "f()"
//
// instead somehow it should be "killed"
//
// check the timestamps in the execution of the test
go inFunc()
case <-quit:
fmt.Println("Stopping the scheduler")
ticker.Stop()
return
}
}
}(f)
return quit
}
何が起こっているかを見るために、私はこのテストを書きました:
func TestSlowExecutions(t *testing.T) {
// log some information using a human readable timestamp
dummyLog := func(format string, a ...interface{}) (n int, err error) {
prefix := fmt.Sprintf("[%v] ", time.Now())
message := fmt.Sprintf(format, a...)
return fmt.Printf("%s%s\n", prefix, message)
}
// UUID to be able to uniquely identify "fooFunc"
newUuid := func() string {
// sudo apt-get install uuid-runtime
uuid, _ := exec.Command("uuidgen").Output()
re := regexp.MustCompile(`\r?\n`)
uuidStr := re.ReplaceAllString(string(uuid), "")
return uuidStr
}
// simulate some sort of very slow execution
fooFunc := func() {
uuid := newUuid()
dummyLog("Ticked")
dummyLog("Starting task %s", uuid)
time.Sleep(2 * time.Second)
dummyLog("Finished task %s", uuid)
}
// test the very slow execution of "fooFunc"
quitChan := schedule(fooFunc, 1*time.Second)
time.Sleep(4 * time.Second)
close(quitChan)
// wait more to see the "closing" message
time.Sleep(4 * time.Second)
}