diff --git a/container/gpool/gpool.go b/container/gpool/gpool.go index e1721de6a..9ee4f80ba 100644 --- a/container/gpool/gpool.go +++ b/container/gpool/gpool.go @@ -8,6 +8,7 @@ package gpool import ( + "context" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" "time" @@ -60,7 +61,7 @@ func New(ttl time.Duration, newFunc NewFunc, expireFunc ...ExpireFunc) *Pool { if len(expireFunc) > 0 { r.ExpireFunc = expireFunc[0] } - gtimer.AddSingleton(time.Second, r.checkExpireItems) + gtimer.AddSingleton(context.Background(), time.Second, r.checkExpireItems) return r } @@ -134,7 +135,7 @@ func (p *Pool) Close() { } // checkExpire removes expired items from pool in every second. -func (p *Pool) checkExpireItems() { +func (p *Pool) checkExpireItems(ctx context.Context) { if p.closed.Val() { // If p has ExpireFunc, // then it must close all items using this function. @@ -157,7 +158,7 @@ func (p *Pool) checkExpireItems() { var latestExpire int64 = -1 // Retrieve the current timestamp in milliseconds, it expires the items // by comparing with this timestamp. It is not accurate comparison for - // every items expired, but high performance. + // every item expired, but high performance. var timestampMilli = gtime.TimestampMilli() for { if latestExpire > timestampMilli { diff --git a/database/gdb/gdb_model_condition.go b/database/gdb/gdb_model_condition.go index 06172dd05..62204b0f4 100644 --- a/database/gdb/gdb_model_condition.go +++ b/database/gdb/gdb_model_condition.go @@ -10,7 +10,6 @@ import ( "fmt" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" - "strings" ) // Where sets the condition statement for the model. The parameter `where` can be type of @@ -266,55 +265,6 @@ func (m *Model) WhereOrNotNull(columns ...string) *Model { return model } -// Group sets the "GROUP BY" statement for the model. -func (m *Model) Group(groupBy ...string) *Model { - if len(groupBy) == 0 { - return m - } - model := m.getModel() - if model.groupBy != "" { - model.groupBy += "," - } - model.groupBy = model.db.GetCore().QuoteString(strings.Join(groupBy, ",")) - return model -} - -// Order sets the "ORDER BY" statement for the model. -func (m *Model) Order(orderBy ...string) *Model { - if len(orderBy) == 0 { - return m - } - model := m.getModel() - if model.orderBy != "" { - model.orderBy += "," - } - model.orderBy = model.db.GetCore().QuoteString(strings.Join(orderBy, " ")) - return model -} - -// OrderAsc sets the "ORDER BY xxx ASC" statement for the model. -func (m *Model) OrderAsc(column string) *Model { - if len(column) == 0 { - return m - } - return m.Order(column + " ASC") -} - -// OrderDesc sets the "ORDER BY xxx DESC" statement for the model. -func (m *Model) OrderDesc(column string) *Model { - if len(column) == 0 { - return m - } - return m.Order(column + " DESC") -} - -// OrderRandom sets the "ORDER BY RANDOM()" statement for the model. -func (m *Model) OrderRandom() *Model { - model := m.getModel() - model.orderBy = "RAND()" - return model -} - // Limit sets the "LIMIT" statement for the model. // The parameter `limit` can be either one or two number, if passed two number is passed, // it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]" diff --git a/database/gdb/gdb_model_order_group.go b/database/gdb/gdb_model_order_group.go new file mode 100644 index 000000000..e212bc070 --- /dev/null +++ b/database/gdb/gdb_model_order_group.go @@ -0,0 +1,63 @@ +// 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 gdb + +import "strings" + +// Order sets the "ORDER BY" statement for the model. +// +// Eg: +// Order("id desc") +// Order("id", "desc") +// Order("id desc,name asc") +func (m *Model) Order(orderBy ...string) *Model { + if len(orderBy) == 0 { + return m + } + model := m.getModel() + if model.orderBy != "" { + model.orderBy += "," + } + model.orderBy = model.db.GetCore().QuoteString(strings.Join(orderBy, " ")) + return model +} + +// OrderAsc sets the "ORDER BY xxx ASC" statement for the model. +func (m *Model) OrderAsc(column string) *Model { + if len(column) == 0 { + return m + } + return m.Order(column + " ASC") +} + +// OrderDesc sets the "ORDER BY xxx DESC" statement for the model. +func (m *Model) OrderDesc(column string) *Model { + if len(column) == 0 { + return m + } + return m.Order(column + " DESC") +} + +// OrderRandom sets the "ORDER BY RANDOM()" statement for the model. +func (m *Model) OrderRandom() *Model { + model := m.getModel() + model.orderBy = "RAND()" + return model +} + +// Group sets the "GROUP BY" statement for the model. +func (m *Model) Group(groupBy ...string) *Model { + if len(groupBy) == 0 { + return m + } + model := m.getModel() + if model.groupBy != "" { + model.groupBy += "," + } + model.groupBy = model.db.GetCore().QuoteString(strings.Join(groupBy, ",")) + return model +} diff --git a/net/ghttp/ghttp_middleware_tracing.go b/net/ghttp/ghttp_middleware_tracing.go index 08a3c8716..8826edf15 100644 --- a/net/ghttp/ghttp_middleware_tracing.go +++ b/net/ghttp/ghttp_middleware_tracing.go @@ -43,9 +43,14 @@ func MiddlewareClientTracing(c *Client, r *http.Request) (*ClientResponse, error // MiddlewareServerTracing is a serer middleware that enables tracing feature using standards of OpenTelemetry. func MiddlewareServerTracing(r *Request) { - tr := otel.GetTracerProvider().Tracer(tracingInstrumentName, trace.WithInstrumentationVersion(gf.VERSION)) - ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header)) - ctx, span := tr.Start(ctx, r.URL.String(), trace.WithSpanKind(trace.SpanKindServer)) + var ( + tr = otel.GetTracerProvider().Tracer(tracingInstrumentName, trace.WithInstrumentationVersion(gf.VERSION)) + ctx, span = tr.Start( + otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header)), + r.URL.String(), + trace.WithSpanKind(trace.SpanKindServer), + ) + ) defer span.End() span.SetAttributes(gtrace.CommonLabels()...) diff --git a/net/ghttp/ghttp_server.go b/net/ghttp/ghttp_server.go index 978c3c6f9..e2d860a9e 100644 --- a/net/ghttp/ghttp_server.go +++ b/net/ghttp/ghttp_server.go @@ -240,9 +240,9 @@ func (s *Server) Start() error { // If this is a child process, it then notifies its parent exit. if gproc.IsChild() { - gtimer.SetTimeout(time.Duration(s.config.GracefulTimeout)*time.Second, func() { + gtimer.SetTimeout(ctx, time.Duration(s.config.GracefulTimeout)*time.Second, func(ctx context.Context) { if err := gproc.Send(gproc.PPid(), []byte("exit"), adminGProcCommGroup); err != nil { - intlog.Error(context.TODO(), "server error in process communication:", err) + intlog.Error(ctx, "server error in process communication:", err) } }) } diff --git a/net/ghttp/ghttp_server_admin.go b/net/ghttp/ghttp_server_admin.go index 5bab11bfc..f8e00350d 100644 --- a/net/ghttp/ghttp_server_admin.go +++ b/net/ghttp/ghttp_server_admin.go @@ -68,7 +68,7 @@ func (p *utilAdmin) Restart(r *Request) { // Shutdown shuts down all the servers. func (p *utilAdmin) Shutdown(r *Request) { - gtimer.SetTimeout(time.Second, func() { + gtimer.SetTimeout(r.Context(), time.Second, func(ctx context.Context) { // It shuts down the server after 1 second, which is not triggered by system signal, // to ensure the response successfully to the client. _ = r.Server.Shutdown() diff --git a/net/ghttp/ghttp_server_admin_process.go b/net/ghttp/ghttp_server_admin_process.go index 6c6eb28aa..02702d56e 100644 --- a/net/ghttp/ghttp_server_admin_process.go +++ b/net/ghttp/ghttp_server_admin_process.go @@ -220,7 +220,7 @@ func restartWebServers(ctx context.Context, signal string, newExeFilePath ...str } else { // Controlled by web page. // It should ensure the response wrote to client and then close all servers gracefully. - gtimer.SetTimeout(time.Second, func() { + gtimer.SetTimeout(ctx, time.Second, func(ctx context.Context) { forceCloseWebServers(ctx) if err := forkRestartProcess(ctx, newExeFilePath...); err != nil { intlog.Error(ctx, err) @@ -252,7 +252,7 @@ func shutdownWebServers(ctx context.Context, signal ...string) { allDoneChan <- struct{}{} } else { glog.Printf(ctx, "%d: server shutting down by api", gproc.Pid()) - gtimer.SetTimeout(time.Second, func() { + gtimer.SetTimeout(ctx, time.Second, func(ctx context.Context) { forceCloseWebServers(ctx) allDoneChan <- struct{}{} }) diff --git a/os/gcache/gcache_adapter_memory.go b/os/gcache/gcache_adapter_memory.go index cb55c5f59..767db7baf 100644 --- a/os/gcache/gcache_adapter_memory.go +++ b/os/gcache/gcache_adapter_memory.go @@ -394,7 +394,7 @@ func (c *AdapterMemory) makeExpireKey(expire int64) int64 { // 1. Asynchronously process the data in the event list, // and synchronize the results to the `expireTimes` and `expireSets` properties. // 2. Clean up the expired key-value pair data. -func (c *AdapterMemory) syncEventAndClearExpired() { +func (c *AdapterMemory) syncEventAndClearExpired(ctx context.Context) { if c.closed.Val() { gtimer.Exit() return diff --git a/os/gcache/gcache_adapter_memory_lru.go b/os/gcache/gcache_adapter_memory_lru.go index ac73da295..d44ceaed6 100644 --- a/os/gcache/gcache_adapter_memory_lru.go +++ b/os/gcache/gcache_adapter_memory_lru.go @@ -7,6 +7,7 @@ package gcache import ( + "context" "time" "github.com/gogf/gf/v2/container/glist" @@ -34,7 +35,7 @@ func newMemCacheLru(cache *AdapterMemory) *adapterMemoryLru { rawList: glist.New(true), closed: gtype.NewBool(), } - gtimer.AddSingleton(time.Second, lru.SyncAndClear) + gtimer.AddSingleton(context.Background(), time.Second, lru.SyncAndClear) return lru } @@ -80,7 +81,7 @@ func (lru *adapterMemoryLru) Pop() interface{} { // SyncAndClear synchronizes the keys from `rawList` to `list` and `data` // using Least Recently Used algorithm. -func (lru *adapterMemoryLru) SyncAndClear() { +func (lru *adapterMemoryLru) SyncAndClear(ctx context.Context) { if lru.closed.Val() { gtimer.Exit() return @@ -89,7 +90,7 @@ func (lru *adapterMemoryLru) SyncAndClear() { for { if v := lru.rawList.PopFront(); v != nil { // Deleting the key from list. - if v := lru.data.Get(v); v != nil { + if v = lru.data.Get(v); v != nil { lru.list.Remove(v.(*glist.Element)) } // Pushing key to the head of the list diff --git a/os/gcache/gcache_cache.go b/os/gcache/gcache_cache.go index af84d9f63..69221a5a9 100644 --- a/os/gcache/gcache_cache.go +++ b/os/gcache/gcache_cache.go @@ -30,7 +30,7 @@ func New(lruCap ...int) *Cache { } // Here may be a "timer leak" if adapter is manually changed from memory adapter. // Do not worry about this, as adapter is less changed, and it does nothing if it's not used. - gtimer.AddSingleton(time.Second, memAdapter.syncEventAndClearExpired) + gtimer.AddSingleton(context.Background(), time.Second, memAdapter.syncEventAndClearExpired) return c } diff --git a/os/gcron/gcron.go b/os/gcron/gcron.go index 6d379496d..ed53e0a8a 100644 --- a/os/gcron/gcron.go +++ b/os/gcron/gcron.go @@ -8,6 +8,7 @@ package gcron import ( + "context" "github.com/gogf/gf/v2/os/glog" "time" @@ -39,52 +40,52 @@ func GetLogger() *glog.Logger { // Add adds a timed task to default cron object. // A unique `name` can be bound with the timed task. // It returns and error if the `name` is already used. -func Add(pattern string, job func(), name ...string) (*Entry, error) { - return defaultCron.Add(pattern, job, name...) +func Add(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) { + return defaultCron.Add(ctx, pattern, job, name...) } // AddSingleton adds a singleton timed task, to default cron object. // A singleton timed task is that can only be running one single instance at the same time. // A unique `name` can be bound with the timed task. // It returns and error if the `name` is already used. -func AddSingleton(pattern string, job func(), name ...string) (*Entry, error) { - return defaultCron.AddSingleton(pattern, job, name...) +func AddSingleton(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) { + return defaultCron.AddSingleton(ctx, pattern, job, name...) } // AddOnce adds a timed task which can be run only once, to default cron object. // A unique `name` can be bound with the timed task. // It returns and error if the `name` is already used. -func AddOnce(pattern string, job func(), name ...string) (*Entry, error) { - return defaultCron.AddOnce(pattern, job, name...) +func AddOnce(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) { + return defaultCron.AddOnce(ctx, pattern, job, name...) } // AddTimes adds a timed task which can be run specified times, to default cron object. // A unique `name` can be bound with the timed task. // It returns and error if the `name` is already used. -func AddTimes(pattern string, times int, job func(), name ...string) (*Entry, error) { - return defaultCron.AddTimes(pattern, times, job, name...) +func AddTimes(ctx context.Context, pattern string, times int, job JobFunc, name ...string) (*Entry, error) { + return defaultCron.AddTimes(ctx, pattern, times, job, name...) } // DelayAdd adds a timed task to default cron object after `delay` time. -func DelayAdd(delay time.Duration, pattern string, job func(), name ...string) { - defaultCron.DelayAdd(delay, pattern, job, name...) +func DelayAdd(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) { + defaultCron.DelayAdd(ctx, delay, pattern, job, name...) } // DelayAddSingleton adds a singleton timed task after `delay` time to default cron object. -func DelayAddSingleton(delay time.Duration, pattern string, job func(), name ...string) { - defaultCron.DelayAddSingleton(delay, pattern, job, name...) +func DelayAddSingleton(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) { + defaultCron.DelayAddSingleton(ctx, delay, pattern, job, name...) } // DelayAddOnce adds a timed task after `delay` time to default cron object. // This timed task can be run only once. -func DelayAddOnce(delay time.Duration, pattern string, job func(), name ...string) { - defaultCron.DelayAddOnce(delay, pattern, job, name...) +func DelayAddOnce(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) { + defaultCron.DelayAddOnce(ctx, delay, pattern, job, name...) } // DelayAddTimes adds a timed task after `delay` time to default cron object. // This timed task can be run specified times. -func DelayAddTimes(delay time.Duration, pattern string, times int, job func(), name ...string) { - defaultCron.DelayAddTimes(delay, pattern, times, job, name...) +func DelayAddTimes(ctx context.Context, delay time.Duration, pattern string, times int, job JobFunc, name ...string) { + defaultCron.DelayAddTimes(ctx, delay, pattern, times, job, name...) } // Search returns a scheduled task with the specified `name`. diff --git a/os/gcron/gcron_cron.go b/os/gcron/gcron_cron.go index e6885a0db..fddb6bfa2 100644 --- a/os/gcron/gcron_cron.go +++ b/os/gcron/gcron_cron.go @@ -7,6 +7,7 @@ package gcron import ( + "context" "time" "github.com/gogf/gf/v2/container/garray" @@ -43,7 +44,7 @@ func (c *Cron) GetLogger() *glog.Logger { } // AddEntry creates and returns a new Entry object. -func (c *Cron) AddEntry(pattern string, job func(), times int, singleton 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 @@ -54,67 +55,68 @@ func (c *Cron) AddEntry(pattern string, job func(), times int, singleton bool, n if times <= 0 { infinite = true } - return c.doAddEntry(addEntryInput{ - Name: entryName, - Job: job, - Times: times, - Pattern: pattern, - Singleton: singleton, - Infinite: infinite, + return c.doAddEntry(doAddEntryInput{ + Name: entryName, + Job: job, + Ctx: ctx, + Times: times, + Pattern: pattern, + IsSingleton: isSingleton, + Infinite: infinite, }) } // Add adds a timed task. // A unique `name` can be bound with the timed task. // It returns and error if the `name` is already used. -func (c *Cron) Add(pattern string, job func(), name ...string) (*Entry, error) { - return c.AddEntry(pattern, job, -1, false, name...) +func (c *Cron) Add(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) { + return c.AddEntry(ctx, pattern, job, -1, false, name...) } // AddSingleton adds a singleton timed task. // A singleton timed task is that can only be running one single instance at the same time. // A unique `name` can be bound with the timed task. // It returns and error if the `name` is already used. -func (c *Cron) AddSingleton(pattern string, job func(), name ...string) (*Entry, error) { - return c.AddEntry(pattern, job, -1, true, name...) +func (c *Cron) AddSingleton(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) { + return c.AddEntry(ctx, pattern, job, -1, true, name...) } // AddTimes adds a timed task which can be run specified times. // A unique `name` can be bound with the timed task. // It returns and error if the `name` is already used. -func (c *Cron) AddTimes(pattern string, times int, job func(), name ...string) (*Entry, error) { - return c.AddEntry(pattern, job, times, false, name...) +func (c *Cron) AddTimes(ctx context.Context, pattern string, times int, job JobFunc, name ...string) (*Entry, error) { + return c.AddEntry(ctx, pattern, job, times, false, name...) } // AddOnce adds a timed task which can be run only once. // A unique `name` can be bound with the timed task. // It returns and error if the `name` is already used. -func (c *Cron) AddOnce(pattern string, job func(), name ...string) (*Entry, error) { - return c.AddEntry(pattern, job, 1, false, name...) +func (c *Cron) AddOnce(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) { + return c.AddEntry(ctx, pattern, job, 1, false, name...) } // DelayAddEntry adds a timed task after `delay` time. -func (c *Cron) DelayAddEntry(delay time.Duration, pattern string, job func(), times int, singleton bool, name ...string) { - gtimer.AddOnce(delay, func() { - if _, err := c.AddEntry(pattern, job, times, singleton, name...); err != nil { +func (c *Cron) DelayAddEntry(ctx context.Context, delay time.Duration, pattern string, job JobFunc, times int, isSingleton bool, name ...string) { + gtimer.AddOnce(ctx, delay, func(ctx context.Context) { + if _, err := c.AddEntry(ctx, pattern, job, times, isSingleton, name...); err != nil { panic(err) } }) } // DelayAdd adds a timed task after `delay` time. -func (c *Cron) DelayAdd(delay time.Duration, pattern string, job func(), name ...string) { - gtimer.AddOnce(delay, func() { - if _, err := c.Add(pattern, job, name...); err != nil { +func (c *Cron) DelayAdd(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) { + gtimer.AddOnce(ctx, delay, func(ctx context.Context) { + if _, err := c.Add(ctx, pattern, job, name...); err != nil { panic(err) } }) } // DelayAddSingleton adds a singleton timed task after `delay` time. -func (c *Cron) DelayAddSingleton(delay time.Duration, pattern string, job func(), name ...string) { - gtimer.AddOnce(delay, func() { - if _, err := c.AddSingleton(pattern, job, name...); err != nil { +func (c *Cron) DelayAddSingleton(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) { + gtimer.AddOnce(ctx, delay, func(ctx context.Context) { + if _, err := c.AddSingleton(ctx, pattern, job, name...); err != nil { panic(err) } }) @@ -122,9 +124,9 @@ func (c *Cron) DelayAddSingleton(delay time.Duration, pattern string, job func() // DelayAddOnce adds a timed task after `delay` time. // This timed task can be run only once. -func (c *Cron) DelayAddOnce(delay time.Duration, pattern string, job func(), name ...string) { - gtimer.AddOnce(delay, func() { - if _, err := c.AddOnce(pattern, job, name...); err != nil { +func (c *Cron) DelayAddOnce(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) { + gtimer.AddOnce(ctx, delay, func(ctx context.Context) { + if _, err := c.AddOnce(ctx, pattern, job, name...); err != nil { panic(err) } }) @@ -132,9 +134,9 @@ func (c *Cron) DelayAddOnce(delay time.Duration, pattern string, job func(), nam // DelayAddTimes adds a timed task after `delay` time. // This timed task can be run specified times. -func (c *Cron) DelayAddTimes(delay time.Duration, pattern string, times int, job func(), name ...string) { - gtimer.AddOnce(delay, func() { - if _, err := c.AddTimes(pattern, times, job, name...); err != nil { +func (c *Cron) DelayAddTimes(ctx context.Context, delay time.Duration, pattern string, times int, job JobFunc, name ...string) { + gtimer.AddOnce(ctx, delay, func(ctx context.Context) { + if _, err := c.AddTimes(ctx, pattern, times, job, name...); err != nil { panic(err) } }) diff --git a/os/gcron/gcron_entry.go b/os/gcron/gcron_entry.go index a2967e6e7..79e13754f 100644 --- a/os/gcron/gcron_entry.go +++ b/os/gcron/gcron_entry.go @@ -19,6 +19,8 @@ import ( "github.com/gogf/gf/v2/util/gconv" ) +type JobFunc = gtimer.JobFunc + // Entry is timing task entry. type Entry struct { cron *Cron // Cron object belonged to. @@ -28,21 +30,22 @@ type Entry struct { times *gtype.Int // Running times limit. infinite *gtype.Bool // No times limit. Name string // Entry name. - Job func() `json:"-"` // Callback function. + Job JobFunc `json:"-"` // Callback function. Time time.Time // Registered time. } -type addEntryInput struct { - Name string // Name names this entry for manual control. - Job func() // Job is the callback function for timed task execution. - Times int // Times specifies the running limit times for the entry. - Pattern string // Pattern is the crontab style string for scheduler. - Singleton bool // Singleton specifies whether timed task executing in singleton mode. - Infinite bool // Infinite specifies whether this entry is running with no times limit. +type doAddEntryInput struct { + Name string // Name names this entry for manual control. + Job JobFunc // Job is the callback function for timed task execution. + Ctx context.Context // The context for the job. + Times int // Times specifies the running limit times for the entry. + Pattern string // Pattern is the crontab style string for scheduler. + IsSingleton bool // Singleton specifies whether timed task executing in singleton mode. + Infinite bool // Infinite specifies whether this entry is running with no times limit. } // doAddEntry creates and returns a new Entry object. -func (c *Cron) doAddEntry(in addEntryInput) (*Entry, error) { +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) @@ -72,7 +75,14 @@ func (c *Cron) doAddEntry(in addEntryInput) (*Entry, error) { // It cannot start running when added to timer. // It should start running after the entry is added to the Cron entries map, to avoid the task // from running during adding where the entries do not have the entry information, which might cause panic. - entry.timerEntry = gtimer.AddEntry(time.Second, entry.check, in.Singleton, -1, gtimer.StatusStopped) + entry.timerEntry = gtimer.AddEntry( + in.Ctx, + time.Second, + entry.check, + in.IsSingleton, + -1, + gtimer.StatusStopped, + ) c.entries.Set(entry.Name, entry) entry.timerEntry.Start() return entry, nil @@ -123,10 +133,7 @@ func (entry *Entry) Close() { // check is the core timing task check logic. // The running times limits feature is implemented by gcron.Entry and cannot be implemented by gtimer.Entry. // gcron.Entry relies on gtimer to implement a scheduled task check for gcron.Entry per second. -func (entry *Entry) check() { - var ( - ctx = context.TODO() - ) +func (entry *Entry) check(ctx context.Context) { if entry.schedule.meet(time.Now()) { switch entry.cron.status.Val() { case StatusStopped: @@ -162,7 +169,7 @@ func (entry *Entry) check() { } entry.logDebugf(ctx, "[gcron] %s %s start", entry.schedule.pattern, entry.jobName) - entry.Job() + entry.Job(entry.timerEntry.Ctx()) } } } diff --git a/os/gcron/gcron_unit_1_test.go b/os/gcron/gcron_unit_1_test.go index 43d815216..aef37c6ca 100644 --- a/os/gcron/gcron_unit_1_test.go +++ b/os/gcron/gcron_unit_1_test.go @@ -25,11 +25,11 @@ func TestCron_Add_Close(t *testing.T) { gtest.C(t, func(t *gtest.T) { cron := gcron.New() array := garray.New(true) - _, err1 := cron.Add("* * * * * *", func() { + _, err1 := cron.Add(ctx, "* * * * * *", func(ctx context.Context) { g.Log().Println(ctx, "cron1") array.Append(1) }) - _, err2 := cron.Add("* * * * * *", func() { + _, err2 := cron.Add(ctx, "* * * * * *", func(ctx context.Context) { g.Log().Println(ctx, "cron2") array.Append(1) }, "test") @@ -51,9 +51,9 @@ func TestCron_Add_Close(t *testing.T) { func TestCron_Basic(t *testing.T) { gtest.C(t, func(t *gtest.T) { cron := gcron.New() - cron.Add("* * * * * *", func() {}, "add") + cron.Add(ctx, "* * * * * *", func(ctx context.Context) {}, "add") //fmt.Println("start", time.Now()) - cron.DelayAdd(time.Second, "* * * * * *", func() {}, "delay_add") + cron.DelayAdd(ctx, time.Second, "* * * * * *", func(ctx context.Context) {}, "delay_add") t.Assert(cron.Size(), 1) time.Sleep(1200 * time.Millisecond) t.Assert(cron.Size(), 2) @@ -72,7 +72,7 @@ func TestCron_Remove(t *testing.T) { gtest.C(t, func(t *gtest.T) { cron := gcron.New() array := garray.New(true) - cron.Add("* * * * * *", func() { + cron.Add(ctx, "* * * * * *", func(ctx context.Context) { array.Append(1) }, "add") t.Assert(array.Len(), 0) @@ -90,8 +90,8 @@ func TestCron_AddSingleton(t *testing.T) { // un used, can be removed gtest.C(t, func(t *gtest.T) { cron := gcron.New() - cron.Add("* * * * * *", func() {}, "add") - cron.DelayAdd(time.Second, "* * * * * *", func() {}, "delay_add") + cron.Add(ctx, "* * * * * *", func(ctx context.Context) {}, "add") + cron.DelayAdd(ctx, time.Second, "* * * * * *", func(ctx context.Context) {}, "delay_add") t.Assert(cron.Size(), 1) time.Sleep(1200 * time.Millisecond) t.Assert(cron.Size(), 2) @@ -108,7 +108,7 @@ func TestCron_AddSingleton(t *testing.T) { gtest.C(t, func(t *gtest.T) { cron := gcron.New() array := garray.New(true) - cron.AddSingleton("* * * * * *", func() { + cron.AddSingleton(ctx, "* * * * * *", func(ctx context.Context) { array.Append(1) time.Sleep(50 * time.Second) }) @@ -123,10 +123,10 @@ func TestCron_AddOnce1(t *testing.T) { gtest.C(t, func(t *gtest.T) { cron := gcron.New() array := garray.New(true) - cron.AddOnce("* * * * * *", func() { + cron.AddOnce(ctx, "* * * * * *", func(ctx context.Context) { array.Append(1) }) - cron.AddOnce("* * * * * *", func() { + cron.AddOnce(ctx, "* * * * * *", func(ctx context.Context) { array.Append(1) }) t.Assert(cron.Size(), 2) @@ -140,7 +140,7 @@ func TestCron_AddOnce2(t *testing.T) { gtest.C(t, func(t *gtest.T) { cron := gcron.New() array := garray.New(true) - cron.AddOnce("@every 2s", func() { + cron.AddOnce(ctx, "@every 2s", func(ctx context.Context) { array.Append(1) }) t.Assert(cron.Size(), 1) @@ -154,7 +154,7 @@ func TestCron_AddTimes(t *testing.T) { gtest.C(t, func(t *gtest.T) { cron := gcron.New() array := garray.New(true) - cron.AddTimes("* * * * * *", 2, func() { + cron.AddTimes(ctx, "* * * * * *", 2, func(ctx context.Context) { array.Append(1) }) time.Sleep(3500 * time.Millisecond) @@ -167,7 +167,7 @@ func TestCron_DelayAdd(t *testing.T) { gtest.C(t, func(t *gtest.T) { cron := gcron.New() array := garray.New(true) - cron.DelayAdd(500*time.Millisecond, "* * * * * *", func() { + cron.DelayAdd(ctx, 500*time.Millisecond, "* * * * * *", func(ctx context.Context) { array.Append(1) }) t.Assert(cron.Size(), 0) @@ -184,7 +184,7 @@ func TestCron_DelayAddSingleton(t *testing.T) { gtest.C(t, func(t *gtest.T) { cron := gcron.New() array := garray.New(true) - cron.DelayAddSingleton(500*time.Millisecond, "* * * * * *", func() { + cron.DelayAddSingleton(ctx, 500*time.Millisecond, "* * * * * *", func(ctx context.Context) { array.Append(1) time.Sleep(10 * time.Second) }) @@ -199,7 +199,7 @@ func TestCron_DelayAddOnce(t *testing.T) { gtest.C(t, func(t *gtest.T) { cron := gcron.New() array := garray.New(true) - cron.DelayAddOnce(500*time.Millisecond, "* * * * * *", func() { + cron.DelayAddOnce(ctx, 500*time.Millisecond, "* * * * * *", func(ctx context.Context) { array.Append(1) }) t.Assert(cron.Size(), 0) @@ -216,7 +216,7 @@ func TestCron_DelayAddTimes(t *testing.T) { gtest.C(t, func(t *gtest.T) { cron := gcron.New() array := garray.New(true) - cron.DelayAddTimes(500*time.Millisecond, "* * * * * *", 2, func() { + cron.DelayAddTimes(ctx, 500*time.Millisecond, "* * * * * *", 2, func(ctx context.Context) { array.Append(1) }) t.Assert(cron.Size(), 0) diff --git a/os/gcron/gcron_unit_2_test.go b/os/gcron/gcron_unit_2_test.go index ef90da631..3c5aa38c5 100644 --- a/os/gcron/gcron_unit_2_test.go +++ b/os/gcron/gcron_unit_2_test.go @@ -7,6 +7,7 @@ package gcron_test import ( + "context" "github.com/gogf/gf/v2/frame/g" "testing" "time" @@ -22,7 +23,7 @@ func TestCron_Entry_Operations(t *testing.T) { cron = gcron.New() array = garray.New(true) ) - cron.DelayAddTimes(500*time.Millisecond, "* * * * * *", 2, func() { + cron.DelayAddTimes(ctx, 500*time.Millisecond, "* * * * * *", 2, func(ctx context.Context) { g.Log().Println(ctx, "add times") array.Append(1) }) @@ -40,7 +41,7 @@ func TestCron_Entry_Operations(t *testing.T) { cron = gcron.New() array = garray.New(true) ) - entry, err1 := cron.Add("* * * * * *", func() { + entry, err1 := cron.Add(ctx, "* * * * * *", func(ctx context.Context) { g.Log().Println(ctx, "add") array.Append(1) }) diff --git a/os/gcron/gcron_z_bench_test.go b/os/gcron/gcron_z_bench_test.go index 4b153f411..287084f24 100644 --- a/os/gcron/gcron_z_bench_test.go +++ b/os/gcron/gcron_z_bench_test.go @@ -7,6 +7,7 @@ package gcron_test import ( + "context" "testing" "github.com/gogf/gf/v2/os/gcron" @@ -14,7 +15,7 @@ import ( func Benchmark_Add(b *testing.B) { for i := 0; i < b.N; i++ { - gcron.Add("1 1 1 1 1 1", func() { + gcron.Add(ctx, "1 1 1 1 1 1", func(ctx context.Context) { }) } diff --git a/os/gcron/gcron_z_example_1_test.go b/os/gcron/gcron_z_example_1_test.go index f9074f248..1826b4010 100644 --- a/os/gcron/gcron_z_example_1_test.go +++ b/os/gcron/gcron_z_example_1_test.go @@ -15,7 +15,7 @@ import ( ) func Example_cronAddSingleton() { - gcron.AddSingleton("* * * * * *", func() { + gcron.AddSingleton(ctx, "* * * * * *", func(ctx context.Context) { glog.Println(context.TODO(), "doing") time.Sleep(2 * time.Second) }) diff --git a/os/glog/glog_logger.go b/os/glog/glog_logger.go index 4c8c604cf..0dd0842e1 100644 --- a/os/glog/glog_logger.go +++ b/os/glog/glog_logger.go @@ -106,7 +106,7 @@ func (l *Logger) print(ctx context.Context, level int, values ...interface{}) { // It just initializes once for each logger. if p.config.RotateSize > 0 || p.config.RotateExpire > 0 { if !p.init.Val() && p.init.Cas(false, true) { - gtimer.AddOnce(p.config.RotateCheckInterval, p.rotateChecksTimely) + gtimer.AddOnce(context.Background(), p.config.RotateCheckInterval, p.rotateChecksTimely) intlog.Printf(ctx, "logger rotation initialized: every %s", p.config.RotateCheckInterval.String()) } } diff --git a/os/glog/glog_logger_rotate.go b/os/glog/glog_logger_rotate.go index ca935bcea..19470606b 100644 --- a/os/glog/glog_logger_rotate.go +++ b/os/glog/glog_logger_rotate.go @@ -106,12 +106,9 @@ func (l *Logger) doRotateFile(ctx context.Context, filePath string) error { } // rotateChecksTimely timely checks the backups expiration and the compression. -func (l *Logger) rotateChecksTimely() { - defer gtimer.AddOnce(l.config.RotateCheckInterval, l.rotateChecksTimely) +func (l *Logger) rotateChecksTimely(ctx context.Context) { + defer gtimer.AddOnce(ctx, l.config.RotateCheckInterval, l.rotateChecksTimely) - var ( - ctx = context.TODO() - ) // Checks whether file rotation not enabled. if l.config.RotateSize <= 0 && l.config.RotateExpire == 0 { intlog.Printf( diff --git a/os/gsession/gsession_storage_file.go b/os/gsession/gsession_storage_file.go index 075d727ab..419af6724 100644 --- a/os/gsession/gsession_storage_file.go +++ b/os/gsession/gsession_storage_file.go @@ -67,12 +67,12 @@ func NewStorageFile(path ...string) *StorageFile { updatingIdSet: gset.NewStrSet(true), } - gtimer.AddSingleton(DefaultStorageFileLoopInterval, s.updateSessionTimely) + gtimer.AddSingleton(context.Background(), DefaultStorageFileLoopInterval, s.updateSessionTimely) return s } // updateSessionTimely batch updates the TTL for sessions timely. -func (s *StorageFile) updateSessionTimely() { +func (s *StorageFile) updateSessionTimely(ctx context.Context) { var ( id string err error diff --git a/os/gsession/gsession_storage_redis.go b/os/gsession/gsession_storage_redis.go index 4a0798e7a..c7c64bd02 100644 --- a/os/gsession/gsession_storage_redis.go +++ b/os/gsession/gsession_storage_redis.go @@ -44,7 +44,7 @@ func NewStorageRedis(redis *gredis.Redis, prefix ...string) *StorageRedis { s.prefix = prefix[0] } // Batch updates the TTL for session ids timely. - gtimer.AddSingleton(DefaultStorageRedisLoopInterval, func() { + gtimer.AddSingleton(context.Background(), DefaultStorageRedisLoopInterval, func(ctx context.Context) { intlog.Print(context.TODO(), "StorageRedis.timer start") var ( id string diff --git a/os/gtimer/gtimer.go b/os/gtimer/gtimer.go index fcd7b3944..6d543c90a 100644 --- a/os/gtimer/gtimer.go +++ b/os/gtimer/gtimer.go @@ -19,6 +19,7 @@ package gtimer import ( + "context" "github.com/gogf/gf/v2/container/gtype" "sync" "time" @@ -64,19 +65,19 @@ func DefaultOptions() TimerOptions { // SetTimeout runs the job once after duration of `delay`. // It is like the one in javascript. -func SetTimeout(delay time.Duration, job JobFunc) { - AddOnce(delay, job) +func SetTimeout(ctx context.Context, delay time.Duration, job JobFunc) { + AddOnce(ctx, delay, job) } // SetInterval runs the job every duration of `delay`. // It is like the one in javascript. -func SetInterval(interval time.Duration, job JobFunc) { - Add(interval, job) +func SetInterval(ctx context.Context, interval time.Duration, job JobFunc) { + Add(ctx, interval, job) } // Add adds a timing job to the default timer, which runs in interval of `interval`. -func Add(interval time.Duration, job JobFunc) *Entry { - return defaultTimer.Add(interval, job) +func Add(ctx context.Context, interval time.Duration, job JobFunc) *Entry { + return defaultTimer.Add(ctx, interval, job) } // AddEntry adds a timing job to the default timer with detailed parameters. @@ -90,53 +91,53 @@ func Add(interval time.Duration, job JobFunc) *Entry { // exits if its run times exceeds the `times`. // // The parameter `status` specifies the job status when it's firstly added to the timer. -func AddEntry(interval time.Duration, job JobFunc, singleton bool, times int, status int) *Entry { - return defaultTimer.AddEntry(interval, job, singleton, times, status) +func AddEntry(ctx context.Context, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) *Entry { + return defaultTimer.AddEntry(ctx, interval, job, isSingleton, times, status) } // AddSingleton is a convenience function for add singleton mode job. -func AddSingleton(interval time.Duration, job JobFunc) *Entry { - return defaultTimer.AddSingleton(interval, job) +func AddSingleton(ctx context.Context, interval time.Duration, job JobFunc) *Entry { + return defaultTimer.AddSingleton(ctx, interval, job) } // AddOnce is a convenience function for adding a job which only runs once and then exits. -func AddOnce(interval time.Duration, job JobFunc) *Entry { - return defaultTimer.AddOnce(interval, job) +func AddOnce(ctx context.Context, interval time.Duration, job JobFunc) *Entry { + return defaultTimer.AddOnce(ctx, interval, job) } // AddTimes is a convenience function for adding a job which is limited running times. -func AddTimes(interval time.Duration, times int, job JobFunc) *Entry { - return defaultTimer.AddTimes(interval, times, job) +func AddTimes(ctx context.Context, interval time.Duration, times int, job JobFunc) *Entry { + return defaultTimer.AddTimes(ctx, interval, times, job) } // DelayAdd adds a timing job after delay of `interval` duration. // Also see Add. -func DelayAdd(delay time.Duration, interval time.Duration, job JobFunc) { - defaultTimer.DelayAdd(delay, interval, job) +func DelayAdd(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) { + defaultTimer.DelayAdd(ctx, delay, interval, job) } // DelayAddEntry adds a timing job after delay of `interval` duration. // Also see AddEntry. -func DelayAddEntry(delay time.Duration, interval time.Duration, job JobFunc, singleton bool, times int, status int) { - defaultTimer.DelayAddEntry(delay, interval, job, singleton, times, status) +func DelayAddEntry(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) { + defaultTimer.DelayAddEntry(ctx, delay, interval, job, isSingleton, times, status) } // DelayAddSingleton adds a timing job after delay of `interval` duration. // Also see AddSingleton. -func DelayAddSingleton(delay time.Duration, interval time.Duration, job JobFunc) { - defaultTimer.DelayAddSingleton(delay, interval, job) +func DelayAddSingleton(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) { + defaultTimer.DelayAddSingleton(ctx, delay, interval, job) } // DelayAddOnce adds a timing job after delay of `interval` duration. // Also see AddOnce. -func DelayAddOnce(delay time.Duration, interval time.Duration, job JobFunc) { - defaultTimer.DelayAddOnce(delay, interval, job) +func DelayAddOnce(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) { + defaultTimer.DelayAddOnce(ctx, delay, interval, job) } // DelayAddTimes adds a timing job after delay of `interval` duration. // Also see AddTimes. -func DelayAddTimes(delay time.Duration, interval time.Duration, times int, job JobFunc) { - defaultTimer.DelayAddTimes(delay, interval, times, job) +func DelayAddTimes(ctx context.Context, delay time.Duration, interval time.Duration, times int, job JobFunc) { + defaultTimer.DelayAddTimes(ctx, delay, interval, times, job) } // Exit is used in timing job internally, which exits and marks it closed from timer. diff --git a/os/gtimer/gtimer_entry.go b/os/gtimer/gtimer_entry.go index 9369d5f1a..9f645a4d9 100644 --- a/os/gtimer/gtimer_entry.go +++ b/os/gtimer/gtimer_entry.go @@ -7,23 +7,25 @@ package gtimer import ( + "context" "github.com/gogf/gf/v2/container/gtype" ) // Entry is the timing job. type Entry struct { - job JobFunc // The job function. - timer *Timer // Belonged timer. - ticks int64 // The job runs every tick. - times *gtype.Int // Limit running times. - status *gtype.Int // Job status. - singleton *gtype.Bool // Singleton mode. - nextTicks *gtype.Int64 // Next run ticks of the job. - infinite *gtype.Bool // No times limit. + job JobFunc // The job function. + ctx context.Context // The context for the job. + timer *Timer // Belonged timer. + ticks int64 // The job runs every tick. + times *gtype.Int // Limit running times. + status *gtype.Int // Job status. + isSingleton *gtype.Bool // Singleton mode. + nextTicks *gtype.Int64 // Next run ticks of the job. + infinite *gtype.Bool // No times limit. } // JobFunc is the job function. -type JobFunc = func() +type JobFunc = func(ctx context.Context) // Status returns the status of the job. func (entry *Entry) Status() int { @@ -54,7 +56,7 @@ func (entry *Entry) Run() { entry.SetStatus(StatusReady) } }() - entry.job() + entry.job(entry.ctx) }() } @@ -113,12 +115,12 @@ func (entry *Entry) Reset() { // IsSingleton checks and returns whether the job in singleton mode. func (entry *Entry) IsSingleton() bool { - return entry.singleton.Val() + return entry.isSingleton.Val() } // SetSingleton sets the job singleton mode. func (entry *Entry) SetSingleton(enabled bool) { - entry.singleton.Set(enabled) + entry.isSingleton.Set(enabled) } // Job returns the job function of this job. @@ -126,6 +128,11 @@ func (entry *Entry) Job() JobFunc { return entry.job } +// Ctx returns the initialized context of this job. +func (entry *Entry) Ctx() context.Context { + return entry.ctx +} + // SetTimes sets the limit running times for the job. func (entry *Entry) SetTimes(times int) { entry.times.Set(times) diff --git a/os/gtimer/gtimer_timer.go b/os/gtimer/gtimer_timer.go index 9dda98d91..385883f65 100644 --- a/os/gtimer/gtimer_timer.go +++ b/os/gtimer/gtimer_timer.go @@ -7,6 +7,7 @@ package gtimer import ( + "context" "github.com/gogf/gf/v2/container/gtype" "time" ) @@ -27,8 +28,15 @@ func New(options ...TimerOptions) *Timer { } // Add adds a timing job to the timer, which runs in interval of `interval`. -func (t *Timer) Add(interval time.Duration, job JobFunc) *Entry { - return t.createEntry(interval, job, false, -1, StatusReady) +func (t *Timer) Add(ctx context.Context, interval time.Duration, job JobFunc) *Entry { + return t.createEntry(createEntryInput{ + Ctx: ctx, + Interval: interval, + Job: job, + IsSingleton: false, + Times: -1, + Status: StatusReady, + }) } // AddEntry adds a timing job to the timer with detailed parameters. @@ -36,68 +44,96 @@ func (t *Timer) Add(interval time.Duration, job JobFunc) *Entry { // The parameter `interval` specifies the running interval of the job. // // The parameter `singleton` specifies whether the job running in singleton mode. -// There's only one of the same job is allowed running when its a singleton mode job. +// There's only one of the same job is allowed running when it's a singleton mode job. // // The parameter `times` specifies limit for the job running times, which means the job // exits if its run times exceeds the `times`. // // The parameter `status` specifies the job status when it's firstly added to the timer. -func (t *Timer) AddEntry(interval time.Duration, job JobFunc, singleton bool, times int, status int) *Entry { - return t.createEntry(interval, job, singleton, times, status) +func (t *Timer) AddEntry(ctx context.Context, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) *Entry { + return t.createEntry(createEntryInput{ + Ctx: ctx, + Interval: interval, + Job: job, + IsSingleton: isSingleton, + Times: times, + Status: status, + }) } // AddSingleton is a convenience function for add singleton mode job. -func (t *Timer) AddSingleton(interval time.Duration, job JobFunc) *Entry { - return t.createEntry(interval, job, true, -1, StatusReady) +func (t *Timer) AddSingleton(ctx context.Context, interval time.Duration, job JobFunc) *Entry { + return t.createEntry(createEntryInput{ + Ctx: ctx, + Interval: interval, + Job: job, + IsSingleton: true, + Times: -1, + Status: StatusReady, + }) } // AddOnce is a convenience function for adding a job which only runs once and then exits. -func (t *Timer) AddOnce(interval time.Duration, job JobFunc) *Entry { - return t.createEntry(interval, job, true, 1, StatusReady) +func (t *Timer) AddOnce(ctx context.Context, interval time.Duration, job JobFunc) *Entry { + return t.createEntry(createEntryInput{ + Ctx: ctx, + Interval: interval, + Job: job, + IsSingleton: true, + Times: 1, + Status: StatusReady, + }) } // AddTimes is a convenience function for adding a job which is limited running times. -func (t *Timer) AddTimes(interval time.Duration, times int, job JobFunc) *Entry { - return t.createEntry(interval, job, true, times, StatusReady) +func (t *Timer) AddTimes(ctx context.Context, interval time.Duration, times int, job JobFunc) *Entry { + return t.createEntry(createEntryInput{ + Ctx: ctx, + Interval: interval, + Job: job, + IsSingleton: true, + Times: times, + Status: StatusReady, + }) } // DelayAdd adds a timing job after delay of `interval` duration. // Also see Add. -func (t *Timer) DelayAdd(delay time.Duration, interval time.Duration, job JobFunc) { - t.AddOnce(delay, func() { - t.Add(interval, job) +func (t *Timer) DelayAdd(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) { + t.AddOnce(ctx, delay, func(ctx context.Context) { + t.Add(ctx, interval, job) }) } // DelayAddEntry adds a timing job after delay of `interval` duration. // Also see AddEntry. -func (t *Timer) DelayAddEntry(delay time.Duration, interval time.Duration, job JobFunc, singleton bool, times int, status int) { - t.AddOnce(delay, func() { - t.AddEntry(interval, job, singleton, times, status) +func (t *Timer) DelayAddEntry(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) { + t.AddOnce(ctx, delay, func(ctx context.Context) { + t.AddEntry(ctx, interval, job, isSingleton, times, status) }) } // DelayAddSingleton adds a timing job after delay of `interval` duration. // Also see AddSingleton. -func (t *Timer) DelayAddSingleton(delay time.Duration, interval time.Duration, job JobFunc) { - t.AddOnce(delay, func() { - t.AddSingleton(interval, job) +func (t *Timer) DelayAddSingleton(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) { + t.AddOnce(ctx, delay, func(ctx context.Context) { + t.AddSingleton(ctx, interval, job) }) } // DelayAddOnce adds a timing job after delay of `interval` duration. // Also see AddOnce. -func (t *Timer) DelayAddOnce(delay time.Duration, interval time.Duration, job JobFunc) { - t.AddOnce(delay, func() { - t.AddOnce(interval, job) +func (t *Timer) DelayAddOnce(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) { + t.AddOnce(ctx, delay, func(ctx context.Context) { + t.AddOnce(ctx, interval, job) }) } // DelayAddTimes adds a timing job after delay of `interval` duration. // Also see AddTimes. -func (t *Timer) DelayAddTimes(delay time.Duration, interval time.Duration, times int, job JobFunc) { - t.AddOnce(delay, func() { - t.AddTimes(interval, times, job) +func (t *Timer) DelayAddTimes(ctx context.Context, delay time.Duration, interval time.Duration, times int, job JobFunc) { + t.AddOnce(ctx, delay, func(ctx context.Context) { + t.AddTimes(ctx, interval, times, job) }) } @@ -116,16 +152,25 @@ func (t *Timer) Close() { t.status.Set(StatusClosed) } +type createEntryInput struct { + Ctx context.Context + Interval time.Duration + Job JobFunc + IsSingleton bool + Times int + Status int +} + // createEntry creates and adds a timing job to the timer. -func (t *Timer) createEntry(interval time.Duration, job JobFunc, singleton bool, times int, status int) *Entry { +func (t *Timer) createEntry(in createEntryInput) *Entry { var ( infinite = false ) - if times <= 0 { + if in.Times <= 0 { infinite = true } var ( - intervalTicksOfJob = int64(interval / t.options.Interval) + intervalTicksOfJob = int64(in.Interval / t.options.Interval) ) if intervalTicksOfJob == 0 { // If the given interval is lesser than the one of the wheel, @@ -135,14 +180,15 @@ func (t *Timer) createEntry(interval time.Duration, job JobFunc, singleton bool, var ( nextTicks = t.ticks.Val() + intervalTicksOfJob entry = &Entry{ - job: job, - timer: t, - ticks: intervalTicksOfJob, - times: gtype.NewInt(times), - status: gtype.NewInt(status), - singleton: gtype.NewBool(singleton), - nextTicks: gtype.NewInt64(nextTicks), - infinite: gtype.NewBool(infinite), + job: in.Job, + ctx: in.Ctx, + timer: t, + ticks: intervalTicksOfJob, + times: gtype.NewInt(in.Times), + status: gtype.NewInt(in.Status), + isSingleton: gtype.NewBool(in.IsSingleton), + nextTicks: gtype.NewInt64(nextTicks), + infinite: gtype.NewBool(infinite), } ) t.queue.Push(entry, nextTicks) diff --git a/os/gtimer/gtimer_z_bench_test.go b/os/gtimer/gtimer_z_bench_test.go index 139bf1c4a..c67cd28c3 100644 --- a/os/gtimer/gtimer_z_bench_test.go +++ b/os/gtimer/gtimer_z_bench_test.go @@ -7,17 +7,19 @@ package gtimer import ( + "context" "testing" "time" ) var ( + ctx = context.TODO() timer = New() ) func Benchmark_Add(b *testing.B) { for i := 0; i < b.N; i++ { - timer.Add(time.Hour, func() { + timer.Add(ctx, time.Hour, func(ctx context.Context) { }) } diff --git a/os/gtimer/gtimer_z_example_test.go b/os/gtimer/gtimer_z_example_test.go index cfef7170b..b1e7568c9 100644 --- a/os/gtimer/gtimer_z_example_test.go +++ b/os/gtimer/gtimer_z_example_test.go @@ -7,6 +7,7 @@ package gtimer_test import ( + "context" "fmt" "time" @@ -14,9 +15,12 @@ import ( ) func Example_add() { - now := time.Now() - interval := 1400 * time.Millisecond - gtimer.Add(interval, func() { + var ( + ctx = context.Background() + now = time.Now() + interval = 1400 * time.Millisecond + ) + gtimer.Add(ctx, interval, func(ctx context.Context) { fmt.Println(time.Now(), time.Duration(time.Now().UnixNano()-now.UnixNano())) now = time.Now() }) diff --git a/os/gtimer/gtimer_z_unit_api_test.go b/os/gtimer/gtimer_z_unit_api_test.go index dd51f1720..61035c487 100644 --- a/os/gtimer/gtimer_z_unit_api_test.go +++ b/os/gtimer/gtimer_z_unit_api_test.go @@ -9,6 +9,7 @@ package gtimer_test import ( + "context" "testing" "time" @@ -17,10 +18,14 @@ import ( "github.com/gogf/gf/v2/test/gtest" ) +var ( + ctx = context.TODO() +) + func TestSetTimeout(t *testing.T) { gtest.C(t, func(t *gtest.T) { array := garray.New(true) - gtimer.SetTimeout(200*time.Millisecond, func() { + gtimer.SetTimeout(ctx, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) }) time.Sleep(1000 * time.Millisecond) @@ -31,7 +36,7 @@ func TestSetTimeout(t *testing.T) { func TestSetInterval(t *testing.T) { gtest.C(t, func(t *gtest.T) { array := garray.New(true) - gtimer.SetInterval(300*time.Millisecond, func() { + gtimer.SetInterval(ctx, 300*time.Millisecond, func(ctx context.Context) { array.Append(1) }) time.Sleep(1000 * time.Millisecond) @@ -42,7 +47,7 @@ func TestSetInterval(t *testing.T) { func TestAddEntry(t *testing.T) { gtest.C(t, func(t *gtest.T) { array := garray.New(true) - gtimer.AddEntry(200*time.Millisecond, func() { + gtimer.AddEntry(ctx, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) }, false, 2, gtimer.StatusReady) time.Sleep(1100 * time.Millisecond) @@ -53,7 +58,7 @@ func TestAddEntry(t *testing.T) { func TestAddSingleton(t *testing.T) { gtest.C(t, func(t *gtest.T) { array := garray.New(true) - gtimer.AddSingleton(200*time.Millisecond, func() { + gtimer.AddSingleton(ctx, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) time.Sleep(10000 * time.Millisecond) }) @@ -65,7 +70,7 @@ func TestAddSingleton(t *testing.T) { func TestAddTimes(t *testing.T) { gtest.C(t, func(t *gtest.T) { array := garray.New(true) - gtimer.AddTimes(200*time.Millisecond, 2, func() { + gtimer.AddTimes(ctx, 200*time.Millisecond, 2, func(ctx context.Context) { array.Append(1) }) time.Sleep(1000 * time.Millisecond) @@ -76,7 +81,7 @@ func TestAddTimes(t *testing.T) { func TestDelayAdd(t *testing.T) { gtest.C(t, func(t *gtest.T) { array := garray.New(true) - gtimer.DelayAdd(500*time.Millisecond, 500*time.Millisecond, func() { + gtimer.DelayAdd(ctx, 500*time.Millisecond, 500*time.Millisecond, func(ctx context.Context) { array.Append(1) }) time.Sleep(600 * time.Millisecond) @@ -89,7 +94,7 @@ func TestDelayAdd(t *testing.T) { func TestDelayAddEntry(t *testing.T) { gtest.C(t, func(t *gtest.T) { array := garray.New(true) - gtimer.DelayAddEntry(200*time.Millisecond, 200*time.Millisecond, func() { + gtimer.DelayAddEntry(ctx, 200*time.Millisecond, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) }, false, 2, gtimer.StatusReady) time.Sleep(300 * time.Millisecond) @@ -102,7 +107,7 @@ func TestDelayAddEntry(t *testing.T) { func TestDelayAddSingleton(t *testing.T) { gtest.C(t, func(t *gtest.T) { array := garray.New(true) - gtimer.DelayAddSingleton(500*time.Millisecond, 500*time.Millisecond, func() { + gtimer.DelayAddSingleton(ctx, 500*time.Millisecond, 500*time.Millisecond, func(ctx context.Context) { array.Append(1) time.Sleep(10000 * time.Millisecond) }) @@ -116,7 +121,7 @@ func TestDelayAddSingleton(t *testing.T) { func TestDelayAddOnce(t *testing.T) { gtest.C(t, func(t *gtest.T) { array := garray.New(true) - gtimer.DelayAddOnce(200*time.Millisecond, 200*time.Millisecond, func() { + gtimer.DelayAddOnce(ctx, 200*time.Millisecond, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) }) time.Sleep(300 * time.Millisecond) @@ -129,7 +134,7 @@ func TestDelayAddOnce(t *testing.T) { func TestDelayAddTimes(t *testing.T) { gtest.C(t, func(t *gtest.T) { array := garray.New(true) - gtimer.DelayAddTimes(500*time.Millisecond, 500*time.Millisecond, 2, func() { + gtimer.DelayAddTimes(ctx, 500*time.Millisecond, 500*time.Millisecond, 2, func(ctx context.Context) { array.Append(1) }) time.Sleep(300 * time.Millisecond) diff --git a/os/gtimer/gtimer_z_unit_entry_test.go b/os/gtimer/gtimer_z_unit_entry_test.go index 7fb4ea236..77192568f 100644 --- a/os/gtimer/gtimer_z_unit_entry_test.go +++ b/os/gtimer/gtimer_z_unit_entry_test.go @@ -9,6 +9,7 @@ package gtimer_test import ( + "context" "testing" "time" @@ -21,7 +22,7 @@ func TestJob_Start_Stop_Close(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - job := timer.Add(200*time.Millisecond, func() { + job := timer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) }) time.Sleep(250 * time.Millisecond) @@ -44,7 +45,7 @@ func TestJob_Singleton(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - job := timer.Add(200*time.Millisecond, func() { + job := timer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) time.Sleep(10 * time.Second) }) @@ -63,7 +64,7 @@ func TestJob_SetTimes(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - job := timer.Add(200*time.Millisecond, func() { + job := timer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) }) job.SetTimes(2) @@ -77,10 +78,10 @@ func TestJob_Run(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - job := timer.Add(1000*time.Millisecond, func() { + job := timer.Add(ctx, 1000*time.Millisecond, func(ctx context.Context) { array.Append(1) }) - job.Job()() + job.Job()(ctx) t.Assert(array.Len(), 1) }) } diff --git a/os/gtimer/gtimer_z_unit_timer_internal_test.go b/os/gtimer/gtimer_z_unit_timer_internal_test.go index a8a2c4db6..5748cf908 100644 --- a/os/gtimer/gtimer_z_unit_timer_internal_test.go +++ b/os/gtimer/gtimer_z_unit_timer_internal_test.go @@ -7,6 +7,7 @@ package gtimer import ( + "context" "github.com/gogf/gf/v2/container/garray" "github.com/gogf/gf/v2/test/gtest" "testing" @@ -19,7 +20,7 @@ func TestTimer_Proceed(t *testing.T) { timer := New(TimerOptions{ Interval: time.Hour, }) - timer.Add(10000*time.Hour, func() { + timer.Add(ctx, 10000*time.Hour, func(ctx context.Context) { array.Append(1) }) timer.proceed(10001) @@ -34,7 +35,7 @@ func TestTimer_Proceed(t *testing.T) { timer := New(TimerOptions{ Interval: time.Millisecond * 100, }) - timer.Add(10000*time.Hour, func() { + timer.Add(ctx, 10000*time.Hour, func(ctx context.Context) { array.Append(1) }) ticks := int64((10000 * time.Hour) / (time.Millisecond * 100)) diff --git a/os/gtimer/gtimer_z_unit_timer_test.go b/os/gtimer/gtimer_z_unit_timer_test.go index 05663dba7..222e143cd 100644 --- a/os/gtimer/gtimer_z_unit_timer_test.go +++ b/os/gtimer/gtimer_z_unit_timer_test.go @@ -9,6 +9,7 @@ package gtimer_test import ( + "context" "testing" "time" @@ -26,15 +27,15 @@ func TestTimer_Add_Close(t *testing.T) { timer := New() array := garray.New(true) //fmt.Println("start", time.Now()) - timer.Add(200*time.Millisecond, func() { + timer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) { //fmt.Println("job1", time.Now()) array.Append(1) }) - timer.Add(200*time.Millisecond, func() { + timer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) { //fmt.Println("job2", time.Now()) array.Append(1) }) - timer.Add(400*time.Millisecond, func() { + timer.Add(ctx, 400*time.Millisecond, func(ctx context.Context) { //fmt.Println("job3", time.Now()) array.Append(1) }) @@ -54,7 +55,7 @@ func TestTimer_Start_Stop_Close(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - timer.Add(1000*time.Millisecond, func() { + timer.Add(ctx, 1000*time.Millisecond, func(ctx context.Context) { array.Append(1) }) t.Assert(array.Len(), 0) @@ -76,7 +77,7 @@ func TestJob_Reset(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - job := timer.AddSingleton(500*time.Millisecond, func() { + job := timer.AddSingleton(ctx, 500*time.Millisecond, func(ctx context.Context) { array.Append(1) }) time.Sleep(300 * time.Millisecond) @@ -94,7 +95,7 @@ func TestTimer_AddSingleton(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - timer.AddSingleton(200*time.Millisecond, func() { + timer.AddSingleton(ctx, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) time.Sleep(10 * time.Second) }) @@ -110,10 +111,10 @@ func TestTimer_AddOnce(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - timer.AddOnce(200*time.Millisecond, func() { + timer.AddOnce(ctx, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) }) - timer.AddOnce(200*time.Millisecond, func() { + timer.AddOnce(ctx, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) }) time.Sleep(250 * time.Millisecond) @@ -132,7 +133,7 @@ func TestTimer_AddTimes(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - timer.AddTimes(200*time.Millisecond, 2, func() { + timer.AddTimes(ctx, 200*time.Millisecond, 2, func(ctx context.Context) { array.Append(1) }) time.Sleep(1000 * time.Millisecond) @@ -144,7 +145,7 @@ func TestTimer_DelayAdd(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - timer.DelayAdd(200*time.Millisecond, 200*time.Millisecond, func() { + timer.DelayAdd(ctx, 200*time.Millisecond, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) }) time.Sleep(250 * time.Millisecond) @@ -158,7 +159,7 @@ func TestTimer_DelayAddJob(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - timer.DelayAddEntry(200*time.Millisecond, 200*time.Millisecond, func() { + timer.DelayAddEntry(ctx, 200*time.Millisecond, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) }, false, 100, gtimer.StatusReady) time.Sleep(250 * time.Millisecond) @@ -172,7 +173,7 @@ func TestTimer_DelayAddSingleton(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - timer.DelayAddSingleton(200*time.Millisecond, 200*time.Millisecond, func() { + timer.DelayAddSingleton(ctx, 200*time.Millisecond, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) time.Sleep(10 * time.Second) }) @@ -188,7 +189,7 @@ func TestTimer_DelayAddOnce(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - timer.DelayAddOnce(200*time.Millisecond, 200*time.Millisecond, func() { + timer.DelayAddOnce(ctx, 200*time.Millisecond, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) }) time.Sleep(250 * time.Millisecond) @@ -206,7 +207,7 @@ func TestTimer_DelayAddTimes(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - timer.DelayAddTimes(200*time.Millisecond, 500*time.Millisecond, 2, func() { + timer.DelayAddTimes(ctx, 200*time.Millisecond, 500*time.Millisecond, 2, func(ctx context.Context) { array.Append(1) }) time.Sleep(200 * time.Millisecond) @@ -229,7 +230,7 @@ func TestTimer_AddLessThanInterval(t *testing.T) { Interval: 100 * time.Millisecond, }) array := garray.New(true) - timer.Add(20*time.Millisecond, func() { + timer.Add(ctx, 20*time.Millisecond, func(ctx context.Context) { array.Append(1) }) time.Sleep(50 * time.Millisecond) @@ -248,7 +249,7 @@ func TestTimer_AddLeveledJob1(t *testing.T) { timer := New() array := garray.New(true) //glog.Println("start") - timer.DelayAdd(1000*time.Millisecond, 1000*time.Millisecond, func() { + timer.DelayAdd(ctx, 1000*time.Millisecond, 1000*time.Millisecond, func(ctx context.Context) { //glog.Println("add") array.Append(1) }) @@ -264,7 +265,7 @@ func TestTimer_Exit(t *testing.T) { gtest.C(t, func(t *gtest.T) { timer := New() array := garray.New(true) - timer.Add(200*time.Millisecond, func() { + timer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) { array.Append(1) gtimer.Exit() })