diff --git a/example_test.go b/example_test.go index 1441ae1e..a9768b58 100644 --- a/example_test.go +++ b/example_test.go @@ -674,8 +674,20 @@ func ExampleScheduler_Stop() { s.StartAsync() s.Stop() fmt.Println(s.IsRunning()) + + s = gocron.NewScheduler(time.UTC) + + go func() { + time.Sleep(1 * time.Second) + s.Stop() + }() + + s.StartBlocking() + fmt.Println(".Stop() stops the blocking start") + // Output: // false + // .Stop() stops the blocking start } func ExampleScheduler_Sunday() { diff --git a/executor.go b/executor.go index 6d4d8b80..e9aafd57 100644 --- a/executor.go +++ b/executor.go @@ -52,7 +52,7 @@ func (e *executor) start() { if panicHandler != nil { defer func() { - if r := recover(); r != nil { + if r := recover(); r != interface{}(nil) { panicHandler(f.name, r) } }() diff --git a/scheduler.go b/scheduler.go index bf190f92..20ee9457 100644 --- a/scheduler.go +++ b/scheduler.go @@ -36,6 +36,8 @@ type Scheduler struct { waitForInterval bool // defaults jobs to waiting for first interval to start singletonMode bool // defaults all jobs to use SingletonMode() jobCreated bool // so the scheduler knows a job was created prior to calling Every or Cron + + stopChan chan struct{} // stops the scheduler } // days in a week @@ -52,6 +54,7 @@ func NewScheduler(loc *time.Location) *Scheduler { time: &trueTime{}, executor: &executor, tagsUnique: false, + stopChan: make(chan struct{}, 1), } } @@ -62,10 +65,11 @@ func (s *Scheduler) SetMaxConcurrentJobs(n int, mode limitMode) { s.executor.limitMode = mode } -// StartBlocking starts all jobs and blocks the current thread +// StartBlocking starts all jobs and blocks the current thread. +// This blocking method can be stopped with Stop() from a separate goroutine. func (s *Scheduler) StartBlocking() { s.StartAsync() - <-make(chan bool) + <-s.stopChan } // StartAsync starts all jobs without blocking the current thread @@ -807,6 +811,7 @@ func (s *Scheduler) Stop() { func (s *Scheduler) stop() { s.setRunning(false) s.executor.stop() + s.stopChan <- struct{}{} } func (s *Scheduler) doCommon(jobFun interface{}, params ...interface{}) (*Job, error) { diff --git a/scheduler_test.go b/scheduler_test.go index 643d1261..8c3ff05a 100644 --- a/scheduler_test.go +++ b/scheduler_test.go @@ -854,6 +854,20 @@ func TestScheduler_Stop(t *testing.T) { assert.EqualValues(t, 1, atomic.LoadInt32(&i)) }) + t.Run("stops a running scheduler calling .Stop()", func(t *testing.T) { + s := NewScheduler(time.UTC) + + go func() { + time.Sleep(1 * time.Second) + assert.True(t, s.IsRunning()) + s.Stop() + time.Sleep(100 * time.Millisecond) // wait for stop goroutine to catch up + }() + + s.StartBlocking() + log.Println(".Stop() stops the blocking start") + assert.False(t, s.IsRunning()) + }) } func TestScheduler_StartAt(t *testing.T) {