From 4278ff74b487bab7b6c2ab7b90fa6045b961216d Mon Sep 17 00:00:00 2001 From: John Roesler Date: Mon, 27 Oct 2025 14:00:58 -0500 Subject: [PATCH 1/4] tests: add more daylight savings time tests (#891) --- job_test.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/job_test.go b/job_test.go index 7128667..cfe82b7 100644 --- a/job_test.go +++ b/job_test.go @@ -44,6 +44,9 @@ func TestDurationJob_next(t *testing.T) { } func TestDailyJob_next(t *testing.T) { + americaChicago, err := time.LoadLocation("America/Chicago") + require.NoError(t, err) + tests := []struct { name string interval uint @@ -84,6 +87,16 @@ func TestDailyJob_next(t *testing.T) { time.Date(2000, 1, 3, 5, 30, 0, 0, time.UTC), 41 * time.Hour, }, + { + "daily at time with daylight savings time", + 1, + []time.Time{ + time.Date(0, 0, 0, 5, 30, 0, 0, americaChicago), + }, + time.Date(2023, 3, 11, 5, 30, 0, 0, americaChicago), + time.Date(2023, 3, 12, 5, 30, 0, 0, americaChicago), + 23 * time.Hour, + }, } for _, tt := range tests { @@ -101,6 +114,9 @@ func TestDailyJob_next(t *testing.T) { } func TestWeeklyJob_next(t *testing.T) { + americaChicago, err := time.LoadLocation("America/Chicago") + require.NoError(t, err) + tests := []struct { name string interval uint @@ -132,6 +148,17 @@ func TestWeeklyJob_next(t *testing.T) { time.Date(2000, 1, 10, 5, 30, 0, 0, time.UTC), 4 * 24 * time.Hour, }, + { + "last run before daylight savings time, next run after", + 1, + []time.Weekday{time.Saturday}, + []time.Time{ + time.Date(0, 0, 0, 5, 30, 0, 0, americaChicago), + }, + time.Date(2023, 3, 11, 5, 30, 0, 0, americaChicago), + time.Date(2023, 3, 18, 5, 30, 0, 0, americaChicago), + 7*24*time.Hour - time.Hour, + }, } for _, tt := range tests { From 291adb8eeeb68cf3ac630bdf3f6cd99f494ef8f1 Mon Sep 17 00:00:00 2001 From: John Roesler Date: Wed, 5 Nov 2025 12:36:20 -0600 Subject: [PATCH 2/4] doc: add v1 to v2 migration guide (#890) --- migration_v1_to_v2.md | 155 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 migration_v1_to_v2.md diff --git a/migration_v1_to_v2.md b/migration_v1_to_v2.md new file mode 100644 index 0000000..1ee7620 --- /dev/null +++ b/migration_v1_to_v2.md @@ -0,0 +1,155 @@ +# Migration Guide: `gocron` v1 → v2 + +This guide helps you migrate your code from the `v1` branch to the `v2` branch of [go-co-op/gocron](https://github.com/go-co-op/gocron). +Version 2 is a major rewrite focusing on improving the internals of gocron, while also enhancing the user interfaces and error handling. +All major functionality has been ported over. + +--- + +## Table of Contents + +- [Overview of Major Changes](#overview-of-major-changes) +- [Installation](#installation) +- [API Changes](#api-changes) +- [Scheduler Creation](#scheduler-creation) +- [Job Definition](#job-definition) +- [Starting and Stopping the Scheduler](#starting-and-stopping-the-scheduler) +- [Error Handling](#error-handling) +- [Distributed Scheduling](#distributed-scheduling) +- [Examples Migration](#examples-migration) +- [Testing and Validation](#testing-and-validation) +- [Troubleshooting](#troubleshooting) +- [References](#references) + +--- + +## Overview of Major Changes + +- **Breaking API changes**: All major interfaces and types have changed. +- **Improved error reporting**: Most functions now return errors. +- **Job IDs and cancellation**: Jobs have unique IDs and can be cancelled. +- **Distributed and monitored scheduling**: Built-in support for distributed schedulers and job monitors. +- **Context and logging enhancements**: Improved support for cancellation, context, and custom logging interfaces. + +--- + +## Installation + +Update your dependency to v2: + +```sh +go get github.com/go-co-op/gocron/v2 +``` + +**Note:** The import path is `github.com/go-co-op/gocron/v2`. + +--- + +## API Changes + +### 1. Scheduler Creation + +**v1:** +```go +import "github.com/go-co-op/gocron" + +s := gocron.NewScheduler(time.UTC) +``` + +**v2:** +```go +import "github.com/go-co-op/gocron/v2" + +s, err := gocron.NewScheduler() +if err != nil { panic(err) } +``` +- **v2** returns an error on creation. +- **v2** does not require a location/timezone argument. Use `WithLocation()` if needed. + +--- + +### 2. Job Creation + +**v1:** +```go +s.Every(1).Second().Do(taskFunc) +``` + +**v2:** +```go +j, err := s.NewJob( + gocron.DurationJob(1*time.Second), + gocron.NewTask(taskFunc), +) +if err != nil { panic(err) } +``` +- **v2** uses explicit job types (`DurationJob`, `CronJob`, etc). +- **v2** jobs have unique IDs: `j.ID()`. +- **v2** returns an error on job creation. + +#### Cron Expressions + +**v1:** +```go +s.Cron("*/5 * * * *").Do(taskFunc) +``` + +**v2:** +```go +j, err := s.NewJob( + gocron.CronJob("*/5 * * * *"), + gocron.NewTask(taskFunc), +) +``` + +#### Arguments + +**v1:** +```go +s.Every(1).Second().Do(taskFunc, arg1, arg2) +``` + +**v2:** +```go +j, err := s.NewJob( + gocron.DurationJob(1*time.Second), + gocron.NewTask(taskFunc, arg1, arg2), +) +``` + +--- + +### 3. Starting and Stopping the Scheduler + +**v1:** +```go +s.StartAsync() +s.Stop() +``` + +**v2:** +```go +s.Start() +s.Shutdown() +``` + +- Always call `Shutdown()` for graceful cleanup. + +--- + +### 4. Error Handling + +- Most v2 methods return errors. Always check `err`. +- Use `errors.go` for error definitions. + +--- + +## References + +- [v2 API Documentation](https://pkg.go.dev/github.com/go-co-op/gocron/v2) +- [Examples](https://pkg.go.dev/github.com/go-co-op/gocron/v2#pkg-examples) +- [Release Notes](https://github.com/go-co-op/gocron/releases) + +--- + +**If you encounter issues, open a GitHub Issue or consider contributing a fix by checking out the [CONTRIBUTING.md](CONTRIBUTING.md) guide.** From 46660bbfb344f1d254f1d68b499ad53bce5a44be Mon Sep 17 00:00:00 2001 From: OsipovMax <22137131+OsipovMax@users.noreply.github.com> Date: Wed, 5 Nov 2025 22:19:14 +0300 Subject: [PATCH 3/4] fix: limit validation for WithLimitedRuns (#893) Co-authored-by: Maksim Osipov Co-authored-by: John Roesler --- errors.go | 1 + job.go | 3 +++ scheduler_test.go | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/errors.go b/errors.go index f7fbc9a..36f7455 100644 --- a/errors.go +++ b/errors.go @@ -59,6 +59,7 @@ var ( ErrStartTimeLaterThanEndTime = errors.New("gocron: WithStartDateTime: start must not be later than end") ErrStopTimeEarlierThanStartTime = errors.New("gocron: WithStopDateTime: end must not be earlier than start") ErrWithStopTimeoutZeroOrNegative = errors.New("gocron: WithStopTimeout: timeout must be greater than 0") + ErrWithLimitedRunsZero = errors.New("gocron: WithLimitedRuns: limit must be greater than 0") ) // internal errors diff --git a/job.go b/job.go index b89f10d..8bdb3c6 100644 --- a/job.go +++ b/job.go @@ -643,6 +643,9 @@ func WithEventListeners(eventListeners ...EventListener) JobOption { // Upon reaching the limit, the job is removed from the scheduler. func WithLimitedRuns(limit uint) JobOption { return func(j *internalJob, _ time.Time) error { + if limit == 0 { + return ErrWithLimitedRunsZero + } j.limitRunsTo = &limitRunsTo{ limit: limit, runCount: 0, diff --git a/scheduler_test.go b/scheduler_test.go index f6b5240..1ae7431 100644 --- a/scheduler_test.go +++ b/scheduler_test.go @@ -1056,6 +1056,14 @@ func TestScheduler_NewJobErrors(t *testing.T) { []JobOption{WithIdentifier(uuid.Nil)}, ErrWithIdentifierNil, }, + { + "WithLimitedRuns is zero", + DurationJob( + time.Second, + ), + []JobOption{WithLimitedRuns(0)}, + ErrWithLimitedRunsZero, + }, } for _, tt := range tests { From 9b37b3fa08b6707ce2b3c35dece3a9d3d39303ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 13:22:11 -0600 Subject: [PATCH 4/4] build(deps): bump golangci/golangci-lint-action from 8.0.0 to 9.0.0 (#894) Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 8.0.0 to 9.0.0. - [Release notes](https://github.com/golangci/golangci-lint-action/releases) - [Commits](https://github.com/golangci/golangci-lint-action/compare/v8.0.0...v9.0.0) --- updated-dependencies: - dependency-name: golangci/golangci-lint-action dependency-version: 9.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/go_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go_test.yml b/.github/workflows/go_test.yml index e9156df..6451d91 100644 --- a/.github/workflows/go_test.yml +++ b/.github/workflows/go_test.yml @@ -24,7 +24,7 @@ jobs: with: go-version: ${{ matrix.go-version }} - name: golangci-lint - uses: golangci/golangci-lint-action@v8.0.0 + uses: golangci/golangci-lint-action@v9.0.0 with: version: v2.4.0 - name: test