Skip to content

Commit

Permalink
add # for cron pattern that can ignore seconds, which makes the cro…
Browse files Browse the repository at this point in the history
…n pattern running in minimum minute like linux crontab pattern (#3306)
  • Loading branch information
gqcn authored Feb 7, 2024
1 parent 51326f3 commit 5307f07
Show file tree
Hide file tree
Showing 34 changed files with 485 additions and 298 deletions.
14 changes: 14 additions & 0 deletions cmd/gf/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.6.2 h1:A9SPHECm3cu8Px+JmCfU7F9sUM00Azm086V/IGOTjyA=
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.6.2/go.mod h1:uN8UUEk42sgxm7yPucxl94vOjlstJ4TDdmLvP+Ywqxo=
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.6.2 h1:jSeSz2m/8m9h6ijkOp8q10UNHTc+aoU1xhnFrdFsUxI=
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.6.2/go.mod h1:5f28iWJU/fqr9OH90sSV5WgsBYz4cIEYsNRKdCL75LI=
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.2 h1:iCUoR8je08TehU633pj+vmNdQ/qmWLTpHYQx7yERTv8=
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.2/go.mod h1:bPYIZ56MyKvLp1P+EWFpkyJ+wofFF9yxChgr/iScP8A=
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.6.2 h1:f4RcVDNRGH/aCGmnNv/CxZtwNOG1zxNSNoTuFBKPhAc=
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.6.2/go.mod h1:2okN4j0vs8fNAeYsTDYOhQclN0jkcFvv8LEzoKgwtSw=
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.6.2 h1:qXk04hgkn8zPiuwK5EG/0oGf3Fh0MTkw7b5qwaR1+Yo=
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.6.2/go.mod h1:T8ON3Jb2wZuC2qitj8QZSMGFbgLNk2ZQIFRSl1OC8qo=
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.6.2 h1:IljLQPa+34RRHDO3+dOSzN1rUcEG8+MuJ3Zzq3Bvg08=
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.6.2/go.mod h1:S2LEZGkPxA7ZXYDXNxjDPl8LcXdNcM7ODVUqgUz8zpg=
github.com/gogf/gf/v2 v2.6.2 h1:TvI1UEH2RDbgFVlJJjkc/6ct6+5zjbOS5MiJ2ESG8qg=
github.com/gogf/gf/v2 v2.6.2/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f h1:7xfXR/BhG3JDqO1s45n65Oyx9t4E/UqDOXep6jXdLCM=
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f/go.mod h1:HnYoio6S7VaFJdryKcD/r9HgX+4QzYfr00XiXUo/xz0=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
39 changes: 39 additions & 0 deletions example/os/cron/linux-crontab/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package main

import (
"context"
"fmt"

"github.com/gogf/gf/v2/os/gcron"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
)

func main() {
fmt.Println("start:", gtime.Now())
var (
err error
pattern1 = "# * * * * *"
pattern2 = "# */2 * * * *"
)
_, err = gcron.Add(gctx.New(), pattern1, func(ctx context.Context) {
fmt.Println(pattern1, gtime.Now())
})
if err != nil {
panic(err)
}
_, err = gcron.Add(gctx.New(), pattern2, func(ctx context.Context) {
fmt.Println(pattern2, gtime.Now())
})
if err != nil {
panic(err)
}

select {}
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/gogf/gf/contrib/registry/etcd/v2"
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
"github.com/gogf/gf/contrib/trace/otlpgrpc/v2"
"github.com/gogf/gf/example/trace/grpc_with_db/protobuf/user"
"github.com/gogf/gf/example/trace/grpc-with-db/protobuf/user"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/gtrace"
"github.com/gogf/gf/v2/os/gctx"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
"github.com/gogf/gf/contrib/registry/etcd/v2"
"github.com/gogf/gf/contrib/trace/otlpgrpc/v2"
"github.com/gogf/gf/example/trace/grpc_with_db/protobuf/user"
"github.com/gogf/gf/example/trace/grpc-with-db/protobuf/user"

"context"
"fmt"
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions os/gcron/gcron.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ var (
defaultCron = New()
)

// SetLogger sets the logger for cron.
// SetLogger sets the global logger for cron.
func SetLogger(logger glog.ILogger) {
defaultCron.SetLogger(logger)
}

// GetLogger returns the logger in the cron.
// GetLogger returns the global logger in the cron.
func GetLogger() glog.ILogger {
return defaultCron.GetLogger()
}
Expand Down
5 changes: 4 additions & 1 deletion os/gcron/gcron_cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/gogf/gf/v2/os/gtimer"
)

// Cron stores all the cron job entries.
type Cron struct {
idGen *gtype.Int64 // Used for unique name generation.
status *gtype.Int // Timed task status(0: Not Start; 1: Running; 2: Stopped; -1: Closed)
Expand Down Expand Up @@ -44,7 +45,9 @@ func (c *Cron) GetLogger() glog.ILogger {
}

// AddEntry creates and returns a new Entry object.
func (c *Cron) AddEntry(ctx context.Context, pattern string, job JobFunc, times int, isSingleton bool, name ...string) (*Entry, error) {
func (c *Cron) AddEntry(
ctx context.Context, pattern string, job JobFunc, times int, isSingleton bool, name ...string,
) (*Entry, error) {
var (
entryName = ""
infinite = false
Expand Down
85 changes: 45 additions & 40 deletions os/gcron/gcron_entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ type doAddEntryInput struct {
func (c *Cron) doAddEntry(in doAddEntryInput) (*Entry, error) {
if in.Name != "" {
if c.Search(in.Name) != nil {
return nil, gerror.NewCodef(gcode.CodeInvalidOperation, `cron job "%s" already exists`, in.Name)
return nil, gerror.NewCodef(
gcode.CodeInvalidOperation,
`duplicated cron job name "%s", already exists`,
in.Name,
)
}
}
schedule, err := newSchedule(in.Pattern)
Expand Down Expand Up @@ -91,103 +95,104 @@ func (c *Cron) doAddEntry(in doAddEntryInput) (*Entry, error) {
}

// IsSingleton return whether this entry is a singleton timed task.
func (entry *Entry) IsSingleton() bool {
return entry.timerEntry.IsSingleton()
func (e *Entry) IsSingleton() bool {
return e.timerEntry.IsSingleton()
}

// SetSingleton sets the entry running in singleton mode.
func (entry *Entry) SetSingleton(enabled bool) {
entry.timerEntry.SetSingleton(enabled)
func (e *Entry) SetSingleton(enabled bool) {
e.timerEntry.SetSingleton(enabled)
}

// SetTimes sets the times which the entry can run.
func (entry *Entry) SetTimes(times int) {
entry.times.Set(times)
entry.infinite.Set(false)
func (e *Entry) SetTimes(times int) {
e.times.Set(times)
e.infinite.Set(false)
}

// Status returns the status of entry.
func (entry *Entry) Status() int {
return entry.timerEntry.Status()
func (e *Entry) Status() int {
return e.timerEntry.Status()
}

// SetStatus sets the status of the entry.
func (entry *Entry) SetStatus(status int) int {
return entry.timerEntry.SetStatus(status)
func (e *Entry) SetStatus(status int) int {
return e.timerEntry.SetStatus(status)
}

// Start starts running the entry.
func (entry *Entry) Start() {
entry.timerEntry.Start()
func (e *Entry) Start() {
e.timerEntry.Start()
}

// Stop stops running the entry.
func (entry *Entry) Stop() {
entry.timerEntry.Stop()
func (e *Entry) Stop() {
e.timerEntry.Stop()
}

// Close stops and removes the entry from cron.
func (entry *Entry) Close() {
entry.cron.entries.Remove(entry.Name)
entry.timerEntry.Close()
func (e *Entry) Close() {
e.cron.entries.Remove(e.Name)
e.timerEntry.Close()
}

// checkAndRun is the core timing task check logic.
func (entry *Entry) checkAndRun(ctx context.Context) {
// This function is called every second.
func (e *Entry) checkAndRun(ctx context.Context) {
currentTime := time.Now()
if !entry.schedule.checkMeetAndUpdateLastSeconds(ctx, currentTime) {
if !e.schedule.checkMeetAndUpdateLastSeconds(ctx, currentTime) {
return
}
switch entry.cron.status.Val() {
switch e.cron.status.Val() {
case StatusStopped:
return

case StatusClosed:
entry.logDebugf(ctx, `cron job "%s" is removed`, entry.getJobNameWithPattern())
entry.Close()
e.logDebugf(ctx, `cron job "%s" is removed`, e.getJobNameWithPattern())
e.Close()

case StatusReady, StatusRunning:
defer func() {
if exception := recover(); exception != nil {
// Exception caught, it logs the error content to logger in default behavior.
entry.logErrorf(ctx,
e.logErrorf(ctx,
`cron job "%s(%s)" end with error: %+v`,
entry.jobName, entry.schedule.pattern, exception,
e.jobName, e.schedule.pattern, exception,
)
} else {
entry.logDebugf(ctx, `cron job "%s" ends`, entry.getJobNameWithPattern())
e.logDebugf(ctx, `cron job "%s" ends`, e.getJobNameWithPattern())
}
if entry.timerEntry.Status() == StatusClosed {
entry.Close()
if e.timerEntry.Status() == StatusClosed {
e.Close()
}
}()

// Running times check.
if !entry.infinite.Val() {
times := entry.times.Add(-1)
if !e.infinite.Val() {
times := e.times.Add(-1)
if times <= 0 {
if entry.timerEntry.SetStatus(StatusClosed) == StatusClosed || times < 0 {
if e.timerEntry.SetStatus(StatusClosed) == StatusClosed || times < 0 {
return
}
}
}
entry.logDebugf(ctx, `cron job "%s" starts`, entry.getJobNameWithPattern())
entry.Job(ctx)
e.logDebugf(ctx, `cron job "%s" starts`, e.getJobNameWithPattern())
e.Job(ctx)
}
}

func (entry *Entry) getJobNameWithPattern() string {
return fmt.Sprintf(`%s(%s)`, entry.jobName, entry.schedule.pattern)
func (e *Entry) getJobNameWithPattern() string {
return fmt.Sprintf(`%s(%s)`, e.jobName, e.schedule.pattern)
}

func (entry *Entry) logDebugf(ctx context.Context, format string, v ...interface{}) {
if logger := entry.cron.GetLogger(); logger != nil {
func (e *Entry) logDebugf(ctx context.Context, format string, v ...interface{}) {
if logger := e.cron.GetLogger(); logger != nil {
logger.Debugf(ctx, format, v...)
}
}

func (entry *Entry) logErrorf(ctx context.Context, format string, v ...interface{}) {
logger := entry.cron.GetLogger()
func (e *Entry) logErrorf(ctx context.Context, format string, v ...interface{}) {
logger := e.cron.GetLogger()
if logger == nil {
logger = glog.DefaultLogger()
}
Expand Down
Loading

0 comments on commit 5307f07

Please sign in to comment.