Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,26 @@ Please see `examples/main.go` for basic usage.

http.HandleFunc("/debug/cron", m.Handler)
```

## Schedule parser customization

To use non-default schedule parser, invoke the `NewManagerWithParser()` function:

```go
// Init some custom parser,
// see https://pkg.go.dev/github.com/robfig/cron/v3#hdr-Alternative_Formats for more info.
m := cron.NewManagerWithParser(cron.WithParseOptions(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor))

// Or use the predefined one:
m = cron.NewManagerWithParser(cron.ParserWithSeconds)

// Use a schedule format acceptable by the custom parser.
m.AddFunc("f1", "* * * * * *", func(_ context.Context) error {
// Do some important stuff...
return nil
})

if err := m.Run(context.Background()); err != nil {
log.Fatal(err)
}
```
28 changes: 27 additions & 1 deletion cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ var (
ErrDuplicate = errors.New("duplicate cron name")
)

var (
// ParserWithSeconds is a schedule parser with the leading seconds support.
ParserWithSeconds = cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)
)

type (
contextKey string
cronState string
Expand All @@ -48,6 +53,7 @@ func (ss Schedule) IsActive() bool { return ss != Schedule(stateDisabled) && ss
// Manager is a Cron manager with context and middleware support.
type Manager struct {
cron *cron.Cron
parser *cron.Parser
middleware []MiddlewareFunc
jobs []job
muState sync.Mutex
Expand Down Expand Up @@ -78,6 +84,14 @@ func NewManager() *Manager {
}
}

// NewManagerWithParser creates new Manager instance with the custom schedule parser.
func NewManagerWithParser(parser cron.Parser) *Manager {
return &Manager{
cron: cron.New(cron.WithParser(parser)),
parser: &parser,
}
}

// AddFunc adds func to cron.
func (cm *Manager) AddFunc(name string, schedule Schedule, fn Func) {
cm.jobs = append(cm.jobs, newJob(name, schedule, fn, false))
Expand Down Expand Up @@ -106,7 +120,7 @@ func (cm *Manager) validateJobs() (string, error) {

// parse schedule
if job.schedule.IsActive() {
_, err := cron.ParseStandard(job.schedule.String())
_, err := cm.parseSchedule(job.schedule)
if err != nil {
return job.name, err
}
Expand Down Expand Up @@ -189,6 +203,18 @@ func (cm *Manager) Stop() context.Context {
return cm.cron.Stop()
}

// parseSchedule parses the given schedule using the registered Parser or with Standard Parser if none.
func (cm *Manager) parseSchedule(s Schedule) (cron.Schedule, error) {
var fn func(s string) (cron.Schedule, error)
if cm.parser != nil {
fn = cm.parser.Parse
} else {
fn = cron.ParseStandard
}

return fn(s.String())
}

// updateState set.
func (cm *Manager) updateState(idx int, state cronState, err error) {
cm.muState.Lock()
Expand Down
40 changes: 40 additions & 0 deletions cron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,46 @@ func TestManager_Validate(t *testing.T) {
})
}

func TestManager_Options(t *testing.T) {
Convey("Test NewManager with custom parser", t, func() {
m := NewManagerWithParser(ParserWithSeconds)

Convey("When standard schedule format", func() {
m.AddFunc("f1", "0 0 * * *", newCronFunc("f1"))

name, err := m.validateJobs()
So(err, ShouldNotBeNil)
So(name, ShouldEqual, "f1")
})

Convey("When custom schedule format", func() {
m.AddFunc("f2", "10 * * * * *", newCronFunc("f1"))

_, err := m.validateJobs()
So(err, ShouldBeNil)
})
})

Convey("Test NewManager with standard parser", t, func() {
m := NewManager()

Convey("When standard schedule format", func() {
m.AddFunc("f1", "0 0 * * *", newCronFunc("f1"))

_, err := m.validateJobs()
So(err, ShouldBeNil)
})

Convey("When custom schedule format", func() {
m.AddFunc("f2", "10 * * * * *", newCronFunc("f1"))

name, err := m.validateJobs()
So(err, ShouldNotBeNil)
So(name, ShouldEqual, "f2")
})
})
}

func TestManager_Run(t *testing.T) {
Convey("Test validate function", t, func() {
ctx := t.Context()
Expand Down