From 34bf62f07af6c5bfe8732bcee72d406e5b516550 Mon Sep 17 00:00:00 2001 From: Tom Morelly Date: Wed, 8 Jan 2025 13:20:21 +1100 Subject: [PATCH] feat(eventListener): add BeforeJobRunsSkipIfBeforeFuncErrors() --- .github/workflows/file_formatting.yml | 2 +- Makefile | 2 +- example_test.go | 23 +++++++++++++++++++++++ executor.go | 14 +++++++++++++- job.go | 26 ++++++++++++++++++++------ job_test.go | 7 +++++++ 6 files changed, 65 insertions(+), 9 deletions(-) diff --git a/.github/workflows/file_formatting.yml b/.github/workflows/file_formatting.yml index 448affef..e8772a61 100644 --- a/.github/workflows/file_formatting.yml +++ b/.github/workflows/file_formatting.yml @@ -16,4 +16,4 @@ jobs: uses: actions/checkout@v4 - name: verify example_test.go run: | - grep "^func " example_test.go | sort -c + grep "^func [a-z-A-Z]" example_test.go | sort -c diff --git a/Makefile b/Makefile index abaf708a..de747147 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ fmt: @go list -f {{.Dir}} ./... | xargs -I{} gofmt -w -s {} lint: - @grep "^func " example_test.go | sort -c + @grep "^func [a-zA-Z]" example_test.go | sort -c @golangci-lint run test: diff --git a/example_test.go b/example_test.go index fb71c204..b077300d 100644 --- a/example_test.go +++ b/example_test.go @@ -104,6 +104,29 @@ func ExampleBeforeJobRuns() { ) } +func ExampleBeforeJobRunsSkipIfBeforeFuncErrors() { + s, _ := gocron.NewScheduler() + defer func() { _ = s.Shutdown() }() + + _, _ = s.NewJob( + gocron.DurationJob( + time.Second, + ), + gocron.NewTask( + func() { + fmt.Println("Will never run, because before job func errors") + }, + ), + gocron.WithEventListeners( + gocron.BeforeJobRunsSkipIfBeforeFuncErrors( + func(jobID uuid.UUID, jobName string) error { + return fmt.Errorf("error") + }, + ), + ), + ) +} + func ExampleCronJob() { s, _ := gocron.NewScheduler() defer func() { _ = s.Shutdown() }() diff --git a/executor.go b/executor.go index 439cacbc..3a9dc0d3 100644 --- a/executor.go +++ b/executor.go @@ -389,8 +389,21 @@ func (e *executor) runJob(j internalJob, jIn jobIn) { } defer func() { _ = lock.Unlock(j.ctx) }() } + _ = callJobFuncWithParams(j.beforeJobRuns, j.id, j.name) + err := callJobFuncWithParams(j.beforeJobRunsSkipIfBeforeFuncErrors, j.id, j.name) + if err != nil { + e.sendOutForRescheduling(&jIn) + + select { + case e.jobsOutCompleted <- j.id: + case <-e.ctx.Done(): + } + + return + } + e.sendOutForRescheduling(&jIn) select { case e.jobsOutCompleted <- j.id: @@ -398,7 +411,6 @@ func (e *executor) runJob(j internalJob, jIn jobIn) { } startTime := time.Now() - var err error if j.afterJobRunsWithPanic != nil { err = e.callJobWithRecover(j) } else { diff --git a/job.go b/job.go index 4d868e6c..700a0b65 100644 --- a/job.go +++ b/job.go @@ -40,12 +40,13 @@ type internalJob struct { startImmediately bool stopTime time.Time // event listeners - 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) - disabledLocker bool + afterJobRuns func(jobID uuid.UUID, jobName string) + beforeJobRuns func(jobID uuid.UUID, jobName string) + beforeJobRunsSkipIfBeforeFuncErrors func(jobID uuid.UUID, jobName string) error + 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) + disabledLocker bool locker Locker } @@ -724,6 +725,19 @@ func BeforeJobRuns(eventListenerFunc func(jobID uuid.UUID, jobName string)) Even } } +// BeforeJobRunsSkipIfBeforeFuncErrors is used to listen for when a job is about to run and +// then runs the provided function. If the provided function returns an error, the job will be +// rescheduled and the current run will be skipped. +func BeforeJobRunsSkipIfBeforeFuncErrors(eventListenerFunc func(jobID uuid.UUID, jobName string) error) EventListener { + return func(j *internalJob) error { + if eventListenerFunc == nil { + return ErrEventListenerFuncNil + } + j.beforeJobRunsSkipIfBeforeFuncErrors = 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 { diff --git a/job_test.go b/job_test.go index b7294860..f3d960f6 100644 --- a/job_test.go +++ b/job_test.go @@ -482,6 +482,13 @@ func TestWithEventListeners(t *testing.T) { }, ErrEventListenerFuncNil, }, + { + "nil before job runs error listener", + []EventListener{ + BeforeJobRunsSkipIfBeforeFuncErrors(nil), + }, + ErrEventListenerFuncNil, + }, } for _, tt := range tests {