我正在实现一个功能,需要定期从目录中读取文件、解析它们并将其导出到 REST 服务。作为同一部分,我想优雅地处理程序终止(SIGKILL、SIGQUIT 等)。同样,我想知道如何实现基于上下文的进程取消。
为了定期执行流程,我使用 gocron。
func scheduleTask(){
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := gocron.NewScheduler()
s.Every(10).Minutes().Do(processTask, ctx)
s.RunAll() // run immediate
<-s.Start() // schedule
for {
select {
case <-(ctx).Done():
fmt.Print("context done")
s.Remove(processTask)
s.Clear()
cancel()
default:
}
}
}
func processTask(ctx *context.Context){
task.Export(ctx)
}
Run Code Online (Sandbox Code Playgroud)
func Export(ctx *context.Context){
pendingFiles, err := filepath.Glob("/tmp/pending/" + "*_task.json")
//error handling
//as there can be 100s of files, I would like to break the loop when context.Done() to return asap & clean up the resources here as well
for _, fileName := range pendingFiles {
exportItem(fileName string)
}
}
func exportItem(fileName string){
data, err := ReadFile(fileName) //not shown here for brevity
//err handling
err = postHTTPData(string(data)) //not shown for brevity
//err handling
}
Run Code Online (Sandbox Code Playgroud)
对于流程管理,我认为另一个组件是信号的实际处理,以及管理这些信号的上下文。
我不确定 go-cron 的具体细节(他们在 github 上有一个展示其中一些概念的示例),但总的来说,我认为涉及的步骤是:
例子:
sigCh := make(chan os.Signal, 1)
defer close(sigCh)
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT)
<-sigCh
cancel()
Run Code Online (Sandbox Code Playgroud)
我不确定这在 go-cron 的上下文中会是什么样子,但是信号处理代码取消的上下文应该是给定任务和作业的上下文的父级。