doubt
doubt

Reputation: 315

Is there a better alternative to using sleep in go routine

I want to write a worker which does a job say every 1 hour. There has been no crons in our system as of now so don't want to add a cron. Request for suggestion in the followin implementation:

func init(){
     go startWorker()
}

func startWorker(){
     doJob()
     time.Sleep(time.Second * 3600)
}

Is using a sleep a bad idea in a go routine or are there better alternatives to do such stuff. The job of doJob() is to fetch from the DB all the failures that have happened in the last hour and do a retry

Upvotes: 1

Views: 3244

Answers (1)

jch
jch

Reputation: 5651

There are two issues with using time.Sleep in the way you envision, one major and one minor.

You have no way to terminate the goroutine

The goroutine is stuck in an infinite loop, so unless doJob panics, it will never terminate. You should probably pass it a channel that will be closed when the goroutine needs to terminate:

done := make(chan struct{})
go worker(done)
...
close(done)
...
func worker(done <-chan struct{}){
    for {
        doJob()
        timer := time.NewTimer(time.Hour)
        select {
        case <-timer.C:
            // nothing
        case <-done:
            timer.Stop()
            return
        }
    }
}

Or, better yet, using a ticker:

func worker(done <-chan struct{}){
    ticker := time.NewTicker(time.Hour)
    for {
        doJob()
        select {
        case <-ticker.C:
            // nothing
        case <-done:
           ticker.Stop()
           return
        }
    }
}

It is good style here to use defer:

func worker(done <-chan struct{}){
    ticker := time.NewTicker(time.Hour)
    defer ticker.Stop()
    for {
        doJob()
        select {
        case <-ticker.C:
            // nothing
        case <-done:
           return
        }
    }
}

You're wasting a stack

While a goroutine uses negligible CPU resources, it uses a stack, on the order of a dozen kilobytes or so. That's probably not a problem for you, but if it is, and if your application has a main loop, then you can insert your ticker and invocation of doWork into the main select statement of the main loop.

Upvotes: 2

Related Questions