github.com/gogf/gf/v2@v2.7.4/os/gtimer/gtimer_timer.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gtimer
     8  
     9  import (
    10  	"context"
    11  	"time"
    12  
    13  	"github.com/gogf/gf/v2/container/gtype"
    14  )
    15  
    16  // New creates and returns a Timer.
    17  func New(options ...TimerOptions) *Timer {
    18  	t := &Timer{
    19  		queue:  newPriorityQueue(),
    20  		status: gtype.NewInt(StatusRunning),
    21  		ticks:  gtype.NewInt64(),
    22  	}
    23  	if len(options) > 0 {
    24  		t.options = options[0]
    25  		if t.options.Interval == 0 {
    26  			t.options.Interval = defaultInterval
    27  		}
    28  	} else {
    29  		t.options = DefaultOptions()
    30  	}
    31  	go t.loop()
    32  	return t
    33  }
    34  
    35  // Add adds a timing job to the timer, which runs in interval of `interval`.
    36  func (t *Timer) Add(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
    37  	return t.createEntry(createEntryInput{
    38  		Ctx:         ctx,
    39  		Interval:    interval,
    40  		Job:         job,
    41  		IsSingleton: false,
    42  		Times:       -1,
    43  		Status:      StatusReady,
    44  	})
    45  }
    46  
    47  // AddEntry adds a timing job to the timer with detailed parameters.
    48  //
    49  // The parameter `interval` specifies the running interval of the job.
    50  //
    51  // The parameter `singleton` specifies whether the job running in singleton mode.
    52  // There's only one of the same job is allowed running when it's a singleton mode job.
    53  //
    54  // The parameter `times` specifies limit for the job running times, which means the job
    55  // exits if its run times exceeds the `times`.
    56  //
    57  // The parameter `status` specifies the job status when it's firstly added to the timer.
    58  func (t *Timer) AddEntry(ctx context.Context, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) *Entry {
    59  	return t.createEntry(createEntryInput{
    60  		Ctx:         ctx,
    61  		Interval:    interval,
    62  		Job:         job,
    63  		IsSingleton: isSingleton,
    64  		Times:       times,
    65  		Status:      status,
    66  	})
    67  }
    68  
    69  // AddSingleton is a convenience function for add singleton mode job.
    70  func (t *Timer) AddSingleton(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
    71  	return t.createEntry(createEntryInput{
    72  		Ctx:         ctx,
    73  		Interval:    interval,
    74  		Job:         job,
    75  		IsSingleton: true,
    76  		Times:       -1,
    77  		Status:      StatusReady,
    78  	})
    79  }
    80  
    81  // AddOnce is a convenience function for adding a job which only runs once and then exits.
    82  func (t *Timer) AddOnce(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
    83  	return t.createEntry(createEntryInput{
    84  		Ctx:         ctx,
    85  		Interval:    interval,
    86  		Job:         job,
    87  		IsSingleton: true,
    88  		Times:       1,
    89  		Status:      StatusReady,
    90  	})
    91  }
    92  
    93  // AddTimes is a convenience function for adding a job which is limited running times.
    94  func (t *Timer) AddTimes(ctx context.Context, interval time.Duration, times int, job JobFunc) *Entry {
    95  	return t.createEntry(createEntryInput{
    96  		Ctx:         ctx,
    97  		Interval:    interval,
    98  		Job:         job,
    99  		IsSingleton: true,
   100  		Times:       times,
   101  		Status:      StatusReady,
   102  	})
   103  }
   104  
   105  // DelayAdd adds a timing job after delay of `delay` duration.
   106  // Also see Add.
   107  func (t *Timer) DelayAdd(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
   108  	t.AddOnce(ctx, delay, func(ctx context.Context) {
   109  		t.Add(ctx, interval, job)
   110  	})
   111  }
   112  
   113  // DelayAddEntry adds a timing job after delay of `delay` duration.
   114  // Also see AddEntry.
   115  func (t *Timer) DelayAddEntry(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) {
   116  	t.AddOnce(ctx, delay, func(ctx context.Context) {
   117  		t.AddEntry(ctx, interval, job, isSingleton, times, status)
   118  	})
   119  }
   120  
   121  // DelayAddSingleton adds a timing job after delay of `delay` duration.
   122  // Also see AddSingleton.
   123  func (t *Timer) DelayAddSingleton(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
   124  	t.AddOnce(ctx, delay, func(ctx context.Context) {
   125  		t.AddSingleton(ctx, interval, job)
   126  	})
   127  }
   128  
   129  // DelayAddOnce adds a timing job after delay of `delay` duration.
   130  // Also see AddOnce.
   131  func (t *Timer) DelayAddOnce(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
   132  	t.AddOnce(ctx, delay, func(ctx context.Context) {
   133  		t.AddOnce(ctx, interval, job)
   134  	})
   135  }
   136  
   137  // DelayAddTimes adds a timing job after delay of `delay` duration.
   138  // Also see AddTimes.
   139  func (t *Timer) DelayAddTimes(ctx context.Context, delay time.Duration, interval time.Duration, times int, job JobFunc) {
   140  	t.AddOnce(ctx, delay, func(ctx context.Context) {
   141  		t.AddTimes(ctx, interval, times, job)
   142  	})
   143  }
   144  
   145  // Start starts the timer.
   146  func (t *Timer) Start() {
   147  	t.status.Set(StatusRunning)
   148  }
   149  
   150  // Stop stops the timer.
   151  func (t *Timer) Stop() {
   152  	t.status.Set(StatusStopped)
   153  }
   154  
   155  // Close closes the timer.
   156  func (t *Timer) Close() {
   157  	t.status.Set(StatusClosed)
   158  }
   159  
   160  type createEntryInput struct {
   161  	Ctx         context.Context
   162  	Interval    time.Duration
   163  	Job         JobFunc
   164  	IsSingleton bool
   165  	Times       int
   166  	Status      int
   167  }
   168  
   169  // createEntry creates and adds a timing job to the timer.
   170  func (t *Timer) createEntry(in createEntryInput) *Entry {
   171  	var (
   172  		infinite  = false
   173  		nextTicks int64
   174  	)
   175  	if in.Times <= 0 {
   176  		infinite = true
   177  	}
   178  	var (
   179  		intervalTicksOfJob = int64(in.Interval / t.options.Interval)
   180  	)
   181  	if intervalTicksOfJob == 0 {
   182  		// If the given interval is lesser than the one of the wheel,
   183  		// then sets it to one tick, which means it will be run in one interval.
   184  		intervalTicksOfJob = 1
   185  	}
   186  	if t.options.Quick {
   187  		// If the quick mode is enabled, which means it will be run right now.
   188  		// Don't need to wait for the first interval.
   189  		nextTicks = t.ticks.Val()
   190  	} else {
   191  		nextTicks = t.ticks.Val() + intervalTicksOfJob
   192  	}
   193  	var (
   194  		entry = &Entry{
   195  			job:         in.Job,
   196  			ctx:         in.Ctx,
   197  			timer:       t,
   198  			ticks:       intervalTicksOfJob,
   199  			times:       gtype.NewInt(in.Times),
   200  			status:      gtype.NewInt(in.Status),
   201  			isSingleton: gtype.NewBool(in.IsSingleton),
   202  			nextTicks:   gtype.NewInt64(nextTicks),
   203  			infinite:    gtype.NewBool(infinite),
   204  		}
   205  	)
   206  	t.queue.Push(entry, nextTicks)
   207  	return entry
   208  }