Why golang CronJob cannot run within goroutine?

Issue

I use CronJob for starting my task everyday, and my task has several sub-tasks which I plan to use goroutine to run. However, things do not go smoothly.

File Framework

|-gpool
|  -pool.go
|-main.go

main.go

import (
        "code.byted.org/i18n_web/content_import_tool_cronJob/gpool"
        "fmt"
        "github.com/robfig/cron/v3"
        "log"
        "os"
        "runtime"
        "time"
    )
    
    func SeedJob(it string, pool *gpool.Pool){
        fmt.Println("Name item: ", it)
        println(runtime.NumGoroutine())
        pool.Done()
    }
    
    type delayJob struct {
        PagePatternNameList []string
    }
    
    func (j *delayJob) GetPagePatternNameList() {
        //j.PagePatternNameList = dal.GetPagePatternName()
        j.PagePatternNameList = []string{"atama_posts","cchan_posts", "cookdoor_posts", "cookpad_posts",
            "cookpad_recipe_seed", "kurashiru_posts", "lips_all_posts", "lips_product", "lips_product_sku_seed",
            "lips_rank", "press_posts", "voce_all_posts", "zozo_posts_women"}
    }
    
    func (j *delayJob)Run(){
        log.Println("delay Job RUN")
        //time.Sleep(2 * time.Second)
        // startSeedJob
        pool := gpool.New(10)
        println(runtime.NumGoroutine())
        for _, it := range j.PagePatternNameList {
            pool.Add(1)
            go SeedJob(it, pool)
        }
        pool.Wait()
        println(runtime.NumGoroutine())
    }
    
    func main() {
        c := cron.New(
            cron.WithLogger(
                cron.VerbosePrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags))))
    
        _, err := c.AddJob("CRON_TZ=America/New_York @every 2m", cron.NewChain(cron.DelayIfStillRunning(cron.DefaultLogger)).Then(&delayJob{}))
        if err != nil {
            fmt.Println("Cron Job err!")
            return
        }
        fmt.Println("it started")
        c.Start()
    
        defer c.Stop()
    
        time.Sleep(time.Second * 5)
    
    }

pool.go

package gpool
    
    import (
        "sync"
    )
    
    type Pool struct {
        queue chan int
        wg    *sync.WaitGroup
    }
    
    func New(size int) *Pool {
        if size <= 0 {
            size = 1
        }
        return &Pool{
            queue: make(chan int, size),
            wg:    &sync.WaitGroup{},
        }
    }
    
    func (p *Pool) Add(delta int) {
        for i := 0; i < delta; i++ {
            p.queue <- 1
        }
        for i := 0; i > delta; i-- {
            <-p.queue
        }
        p.wg.Add(delta)
    }
    
    func (p *Pool) Done() {
        <-p.queue
        p.wg.Done()
    }
    
    func (p *Pool) Wait() {
        p.wg.Wait()
    }

When I run my code, it did not print out any information I expected, just

it started
cron: 2021/06/10 13:41:21 start
cron: 2021/06/10 13:41:21 schedule, now=2021-06-10T13:41:21+08:00, entry=1, next=2021-06-10T13:43:21+08:00
Exiting.

Debugger finished with the exit code 0

It seems like it did not trigger an err, but not run correctly. How can I solve this?

Solution

It did not run because you scheduled the job to run every 2 minutes and then waited only 5 seconds, then you returned from main() which causes your program to exit.

If you want to start this cron in the background you must keep the program running long enough for it to run and complete, at least more than 2 minutes in this example.

If you have nothing else to do in main() then you might consider using c.Run() rather than c.Start().

Answered By – Bracken

Answer Checked By – David Marino (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.