github.com/wangyougui/gf/v2@v2.6.5/os/gtimer/gtimer_entry.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/wangyougui/gf.
     6  
     7  package gtimer
     8  
     9  import (
    10  	"context"
    11  	"github.com/wangyougui/gf/v2/errors/gcode"
    12  
    13  	"github.com/wangyougui/gf/v2/container/gtype"
    14  	"github.com/wangyougui/gf/v2/errors/gerror"
    15  )
    16  
    17  // Entry is the timing job.
    18  type Entry struct {
    19  	job         JobFunc         // The job function.
    20  	ctx         context.Context // The context for the job, for READ ONLY.
    21  	timer       *Timer          // Belonged timer.
    22  	ticks       int64           // The job runs every tick.
    23  	times       *gtype.Int      // Limit running times.
    24  	status      *gtype.Int      // Job status.
    25  	isSingleton *gtype.Bool     // Singleton mode.
    26  	nextTicks   *gtype.Int64    // Next run ticks of the job.
    27  	infinite    *gtype.Bool     // No times limit.
    28  }
    29  
    30  // JobFunc is the timing called job function in timer.
    31  type JobFunc = func(ctx context.Context)
    32  
    33  // Status returns the status of the job.
    34  func (entry *Entry) Status() int {
    35  	return entry.status.Val()
    36  }
    37  
    38  // Run runs the timer job asynchronously.
    39  func (entry *Entry) Run() {
    40  	if !entry.infinite.Val() {
    41  		leftRunningTimes := entry.times.Add(-1)
    42  		// It checks its running times exceeding.
    43  		if leftRunningTimes < 0 {
    44  			entry.status.Set(StatusClosed)
    45  			return
    46  		}
    47  	}
    48  	go func() {
    49  		defer func() {
    50  			if exception := recover(); exception != nil {
    51  				if exception != panicExit {
    52  					if v, ok := exception.(error); ok && gerror.HasStack(v) {
    53  						panic(v)
    54  					} else {
    55  						panic(gerror.NewCodef(gcode.CodeInternalPanic, "exception recovered: %+v", exception))
    56  					}
    57  				} else {
    58  					entry.Close()
    59  					return
    60  				}
    61  			}
    62  			if entry.Status() == StatusRunning {
    63  				entry.SetStatus(StatusReady)
    64  			}
    65  		}()
    66  		entry.job(entry.ctx)
    67  	}()
    68  }
    69  
    70  // doCheckAndRunByTicks checks the if job can run in given timer ticks,
    71  // it runs asynchronously if the given `currentTimerTicks` meets or else
    72  // it increments its ticks and waits for next running check.
    73  func (entry *Entry) doCheckAndRunByTicks(currentTimerTicks int64) {
    74  	// Ticks check.
    75  	if currentTimerTicks < entry.nextTicks.Val() {
    76  		return
    77  	}
    78  	entry.nextTicks.Set(currentTimerTicks + entry.ticks)
    79  	// Perform job checking.
    80  	switch entry.status.Val() {
    81  	case StatusRunning:
    82  		if entry.IsSingleton() {
    83  			return
    84  		}
    85  	case StatusReady:
    86  		if !entry.status.Cas(StatusReady, StatusRunning) {
    87  			return
    88  		}
    89  	case StatusStopped:
    90  		return
    91  	case StatusClosed:
    92  		return
    93  	}
    94  	// Perform job running.
    95  	entry.Run()
    96  }
    97  
    98  // SetStatus custom sets the status for the job.
    99  func (entry *Entry) SetStatus(status int) int {
   100  	return entry.status.Set(status)
   101  }
   102  
   103  // Start starts the job.
   104  func (entry *Entry) Start() {
   105  	entry.status.Set(StatusReady)
   106  }
   107  
   108  // Stop stops the job.
   109  func (entry *Entry) Stop() {
   110  	entry.status.Set(StatusStopped)
   111  }
   112  
   113  // Close closes the job, and then it will be removed from the timer.
   114  func (entry *Entry) Close() {
   115  	entry.status.Set(StatusClosed)
   116  }
   117  
   118  // Reset resets the job, which resets its ticks for next running.
   119  func (entry *Entry) Reset() {
   120  	entry.nextTicks.Set(entry.timer.ticks.Val() + entry.ticks)
   121  }
   122  
   123  // IsSingleton checks and returns whether the job in singleton mode.
   124  func (entry *Entry) IsSingleton() bool {
   125  	return entry.isSingleton.Val()
   126  }
   127  
   128  // SetSingleton sets the job singleton mode.
   129  func (entry *Entry) SetSingleton(enabled bool) {
   130  	entry.isSingleton.Set(enabled)
   131  }
   132  
   133  // Job returns the job function of this job.
   134  func (entry *Entry) Job() JobFunc {
   135  	return entry.job
   136  }
   137  
   138  // Ctx returns the initialized context of this job.
   139  func (entry *Entry) Ctx() context.Context {
   140  	return entry.ctx
   141  }
   142  
   143  // SetTimes sets the limit running times for the job.
   144  func (entry *Entry) SetTimes(times int) {
   145  	entry.times.Set(times)
   146  	entry.infinite.Set(false)
   147  }