Skip to content

Commit

Permalink
Add AfterJobRunsWithPanic (#733)
Browse files Browse the repository at this point in the history
  • Loading branch information
trungdlp-wolffun authored Jun 20, 2024
1 parent 5f94f39 commit 399ac28
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 9 deletions.
1 change: 1 addition & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var (
ErrWeeklyJobDaysOfTheWeekNil = fmt.Errorf("gocron: WeeklyJob: daysOfTheWeek must not be nil")
ErrWeeklyJobHours = fmt.Errorf("gocron: WeeklyJob: atTimes hours must be between 0 and 23 inclusive")
ErrWeeklyJobMinutesSeconds = fmt.Errorf("gocron: WeeklyJob: atTimes minutes and seconds must be between 0 and 59 inclusive")
ErrPanicRecovered = fmt.Errorf("gocron: panic recovered")
ErrWithClockNil = fmt.Errorf("gocron: WithClock: clock must not be nil")
ErrWithDistributedElectorNil = fmt.Errorf("gocron: WithDistributedElector: elector must not be nil")
ErrWithDistributedLockerNil = fmt.Errorf("gocron: WithDistributedLocker: locker must not be nil")
Expand Down
1 change: 0 additions & 1 deletion examples/elector/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ func main() {
log.Println("run job")
}),
)

if err != nil {
log.Println(err)
return
Expand Down
15 changes: 14 additions & 1 deletion executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ func (e *executor) runJob(j internalJob, jIn jobIn) {
}

startTime := time.Now()
err := callJobFuncWithParams(j.function, j.parameters...)
err := e.callJobWithRecover(j)
if e.monitor != nil {
e.monitor.RecordJobTiming(startTime, time.Now(), j.id, j.name, j.tags)
}
Expand All @@ -381,6 +381,19 @@ func (e *executor) runJob(j internalJob, jIn jobIn) {
}
}

func (e *executor) callJobWithRecover(j internalJob) (err error) {
defer func() {
if recoverData := recover(); recoverData != nil {
_ = callJobFuncWithParams(j.afterJobRunsWithPanic, j.id, j.name, recoverData)

// if panic is occurred, we should return an error
err = ErrPanicRecovered
}
}()

return callJobFuncWithParams(j.function, j.parameters...)
}

func (e *executor) incrementJobCounter(j internalJob, status JobStatus) {
if e.monitor != nil {
e.monitor.IncrementJob(j.id, j.name, j.tags, status)
Expand Down
21 changes: 17 additions & 4 deletions job.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type internalJob struct {
afterJobRuns func(jobID uuid.UUID, jobName string)
beforeJobRuns func(jobID uuid.UUID, jobName string)
afterJobRunsWithError func(jobID uuid.UUID, jobName string, err error)
afterJobRunsWithPanic func(jobID uuid.UUID, jobName string, recoverData any)
afterLockError func(jobID uuid.UUID, jobName string, err error)

locker Locker
Expand Down Expand Up @@ -604,6 +605,18 @@ func WithTags(tags ...string) JobOption {
// listeners that can be used to listen for job events.
type EventListener func(*internalJob) error

// BeforeJobRuns is used to listen for when a job is about to run and
// then run the provided function.
func BeforeJobRuns(eventListenerFunc func(jobID uuid.UUID, jobName string)) EventListener {
return func(j *internalJob) error {
if eventListenerFunc == nil {
return ErrEventListenerFuncNil
}
j.beforeJobRuns = eventListenerFunc
return nil
}
}

// AfterJobRuns is used to listen for when a job has run
// without an error, and then run the provided function.
func AfterJobRuns(eventListenerFunc func(jobID uuid.UUID, jobName string)) EventListener {
Expand All @@ -628,14 +641,14 @@ func AfterJobRunsWithError(eventListenerFunc func(jobID uuid.UUID, jobName strin
}
}

// BeforeJobRuns is used to listen for when a job is about to run and
// then run the provided function.
func BeforeJobRuns(eventListenerFunc func(jobID uuid.UUID, jobName string)) EventListener {
// AfterJobRunsWithPanic is used to listen for when a job has run and
// returned panicked recover data, and then run the provided function.
func AfterJobRunsWithPanic(eventListenerFunc func(jobID uuid.UUID, jobName string, recoverData any)) EventListener {
return func(j *internalJob) error {
if eventListenerFunc == nil {
return ErrEventListenerFuncNil
}
j.beforeJobRuns = eventListenerFunc
j.afterJobRunsWithPanic = eventListenerFunc
return nil
}
}
Expand Down
41 changes: 38 additions & 3 deletions job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,13 @@ func TestWithEventListeners(t *testing.T) {
nil,
nil,
},
{
"beforeJobRuns",
[]EventListener{
BeforeJobRuns(func(_ uuid.UUID, _ string) {}),
},
nil,
},
{
"afterJobRuns",
[]EventListener{
Expand All @@ -431,9 +438,9 @@ func TestWithEventListeners(t *testing.T) {
nil,
},
{
"beforeJobRuns",
"afterJobRunsWithPanic",
[]EventListener{
BeforeJobRuns(func(_ uuid.UUID, _ string) {}),
AfterJobRunsWithPanic(func(_ uuid.UUID, _ string, _ any) {}),
},
nil,
},
Expand Down Expand Up @@ -487,13 +494,16 @@ func TestWithEventListeners(t *testing.T) {
return
}
var count int
if ij.beforeJobRuns != nil {
count++
}
if ij.afterJobRuns != nil {
count++
}
if ij.afterJobRunsWithError != nil {
count++
}
if ij.beforeJobRuns != nil {
if ij.afterJobRunsWithPanic != nil {
count++
}
if ij.afterLockError != nil {
Expand Down Expand Up @@ -633,3 +643,28 @@ func TestJob_NextRuns(t *testing.T) {
})
}
}

func TestJob_PanicOccurred(t *testing.T) {
gotCh := make(chan any)
s := newTestScheduler(t)
_, err := s.NewJob(
DurationJob(10*time.Millisecond),
NewTask(func() {
a := 0
_ = 1 / a
}),
WithEventListeners(
AfterJobRunsWithPanic(func(_ uuid.UUID, _ string, recoverData any) {
gotCh <- recoverData
}),
),
)
require.NoError(t, err)

s.Start()
got := <-gotCh
require.EqualError(t, got.(error), "runtime error: integer divide by zero")

require.NoError(t, s.Shutdown())
close(gotCh)
}

0 comments on commit 399ac28

Please sign in to comment.