Sfoglia il codice sorgente

Recover from panics in cron jobs

Thomas Meire 9 anni fa
parent
commit
634cf55a82
2 ha cambiato i file con 43 aggiunte e 1 eliminazioni
  1. 11 1
      cron.go
  2. 32 0
      cron_test.go

+ 11 - 1
cron.go

@@ -3,6 +3,7 @@
 package cron
 
 import (
+	"fmt"
 	"sort"
 	"time"
 )
@@ -127,6 +128,15 @@ func (c *Cron) Start() {
 	go c.run()
 }
 
+func (c *Cron) runWithRecovery(j Job) {
+	defer func() {
+		if r := recover(); r != nil {
+			fmt.Println("Cron function panicked: ", r)
+		}
+	}()
+	j.Run()
+}
+
 // Run the scheduler.. this is private just due to the need to synchronize
 // access to the 'running' state variable.
 func (c *Cron) run() {
@@ -156,7 +166,7 @@ func (c *Cron) run() {
 				if e.Next != effective {
 					break
 				}
-				go e.Job.Run()
+				go c.runWithRecovery(e.Job)
 				e.Prev = e.Next
 				e.Next = e.Schedule.Next(effective)
 			}

+ 32 - 0
cron_test.go

@@ -12,6 +12,38 @@ import (
 // compensate for a few milliseconds of runtime.
 const ONE_SECOND = 1*time.Second + 10*time.Millisecond
 
+func TestFuncPanicRecovery(t *testing.T) {
+	cron := New()
+	cron.Start()
+	defer cron.Stop()
+	cron.AddFunc("* * * * * ?", func() { panic("YOLO") })
+
+	select {
+	case <-time.After(ONE_SECOND):
+		return
+	}
+}
+
+type DummyJob struct{}
+
+func (d DummyJob) Run() {
+	panic("YOLO")
+}
+
+func TestJobPanicRecovery(t *testing.T) {
+	var job DummyJob
+
+	cron := New()
+	cron.Start()
+	defer cron.Stop()
+	cron.AddJob("* * * * * ?", job)
+
+	select {
+	case <-time.After(ONE_SECOND):
+		return
+	}
+}
+
 // Start and stop cron with no entries.
 func TestNoEntries(t *testing.T) {
 	cron := New()