go例程中基于上下文的长时间运行循环的终止

I'm implementing a feature where I need to read files from a directory, parse and export them to a REST service at a regular interval. As part of the same I would like to gracefully handle the program termination (SIGKILL, SIGQUIT etc). Towards the same I would like to know how to implement Context based cancellation of process.

For executing the flow in regular interval I'm using gocron.

cmd/scheduler.go

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)
}

task/export.go

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
}

For the process management, I think the other component is the actual handling of signals, and managing the context from those signals.

I'm not sure of the specifics of go-cron (they have an example showing some of these concepts on their github) but in general I think that the steps involved are:

  • Registration of os signals handler
  • Waiting to receive a signal
  • Canceling top level context in response to a signal

Example:

sigCh := make(chan os.Signal, 1)
defer close(sigCh)
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT)
<-sigCh
cancel()

I'm not sure how this will look in the context of go-cron, but the context that the signal handling code cancels should be a parent of the context that the task and job is given.