cron icon indicating copy to clipboard operation
cron copied to clipboard

Gracefull stop cronjob

Open quanlndzt opened this issue 9 months ago • 1 comments

Hey team, I have problem with stop cron job. When I stop server while the job is running, it will be force close my job. I want to Gracefull stop the job Does have any solution for this?

Version

  • go 1.24.2
  • github.com/robfig/cron v1.2.0

Code sample

package main

import (
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"github.com/robfig/cron"
)

var (
	cronJob   *cron.Cron
	startOnce sync.Once
	stopOnce  sync.Once
)

func StartCronJobs() {
	startOnce.Do(func() {
		fmt.Println("[StartCronJobs] start cronjob")
		cronJob = cron.New()
		cronJob.Start()
		cronJob.AddFunc("@every 10s", func() {
			fmt.Println("Cron job running at", time.Now())
			TestJob()
			fmt.Println("Cron job running completed at", time.Now())
		})
	})
}

func TestJob() error {
	time.Sleep(7 * time.Second)
	return nil
}

func StopCronJobs() {
	stopOnce.Do(func() {
		fmt.Println("[StopCronJobs] stop at ", time.Now())
		cronJob.Stop()
		fmt.Println("[StopCronJobs] stop completed at", time.Now())
	})
}

func main() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)

	StartCronJobs()

	<-c
	fmt.Println("[Main] stop server")
	StopCronJobs()
	fmt.Println("[Main] stop server completed")
}

Reproduce

  • Run my code
  • When I run my code, when the job is running => Press Ctl +C to cancel the code

Result


[StartCronJobs] start cronjob
Cron job running at 2025-05-22 10:29:44.008364506 +0700 +07 m=+9.570125026
^C[Main] stop server
[StopCronJobs] stop at  2025-05-22 10:29:45.727787596 +0700 +07 m=+11.289548167
[StopCronJobs] stop completed at 2025-05-22 10:29:45.727830408 +0700 +07 m=+11.289590937
[Main] stop server completed

quanlndzt avatar May 22 '25 03:05 quanlndzt

cronJob.Stop() returns a context that waits until all job are done executing

So you could wait for the job to complete using something like <-cronJob.Stop().Done()

But if you want to handle graceful stop in your job, I suggest you look at my fork which allow you to have a context directly in the job function

https://github.com/alaingilbert/cron

cronJob.AddJob("@every 10s", func(ctx context.Context) {
  // you can handle graceful stop using the context
})

alaingilbert avatar Jun 03 '25 23:06 alaingilbert

Solution available in maintained fork

This feature has been implemented in netresearch/go-cron, a maintained fork of this library.

Implementation:

  1. JobWithContext interface - Jobs can implement RunWithContext(ctx context.Context) to receive cancellation signals
  2. WithContext(ctx) option - Sets base context for all jobs
  3. StopWithTimeout(duration) - Graceful shutdown with configurable timeout
  4. StopAndWait() - Convenience method for blocking until all jobs complete
ctx, cancel := context.WithCancel(context.Background())
c := cron.New(cron.WithContext(ctx))

c.AddJob("@every 1m", cron.FuncJobWithContext(func(ctx context.Context) {
    select {
    case <-ctx.Done():
        return // Graceful shutdown
    default:
        // Do work
    }
}))

// Later: graceful shutdown with 30s timeout
if !c.StopWithTimeout(30 * time.Second) {
    log.Println("Warning: some jobs did not complete within 30s")
}

How to migrate:

// Change import from:
import "github.com/robfig/cron/v3"

// To:
import cron "github.com/netresearch/go-cron"

The API is 100% backward compatible. See the migration guide for details.

Related: netresearch/go-cron#16, netresearch/go-cron#102, netresearch/go-cron#103

CybotTM avatar Dec 04 '25 23:12 CybotTM