gf/os/gtimer/gtimer_timer.go
2021-11-15 20:49:02 +08:00

198 lines
5.6 KiB
Go

// 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 gtimer
import (
"context"
"time"
"github.com/gogf/gf/v2/container/gtype"
)
func New(options ...TimerOptions) *Timer {
t := &Timer{
queue: newPriorityQueue(),
status: gtype.NewInt(StatusRunning),
ticks: gtype.NewInt64(),
}
if len(options) > 0 {
t.options = options[0]
} else {
t.options = DefaultOptions()
}
go t.loop()
return t
}
// Add adds a timing job to the timer, which runs in interval of `interval`.
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.
//
// 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 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(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(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(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(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(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(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(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(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(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)
})
}
// Start starts the timer.
func (t *Timer) Start() {
t.status.Set(StatusRunning)
}
// Stop stops the timer.
func (t *Timer) Stop() {
t.status.Set(StatusStopped)
}
// Close closes the timer.
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(in createEntryInput) *Entry {
var (
infinite = false
)
if in.Times <= 0 {
infinite = true
}
var (
intervalTicksOfJob = int64(in.Interval / t.options.Interval)
)
if intervalTicksOfJob == 0 {
// If the given interval is lesser than the one of the wheel,
// then sets it to one tick, which means it will be run in one interval.
intervalTicksOfJob = 1
}
var (
nextTicks = t.ticks.Val() + intervalTicksOfJob
entry = &Entry{
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)
return entry
}