github.com/gogf/gf/v2@v2.7.4/os/gcron/gcron_cron.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 gcron
     8  
     9  import (
    10  	"context"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/gogf/gf/v2/container/garray"
    15  	"github.com/gogf/gf/v2/container/gmap"
    16  	"github.com/gogf/gf/v2/container/gtype"
    17  	"github.com/gogf/gf/v2/os/glog"
    18  	"github.com/gogf/gf/v2/os/gtimer"
    19  )
    20  
    21  // Cron stores all the cron job entries.
    22  type Cron struct {
    23  	idGen     *gtype.Int64    // Used for unique name generation.
    24  	status    *gtype.Int      // Timed task status(0: Not Start; 1: Running; 2: Stopped; -1: Closed)
    25  	entries   *gmap.StrAnyMap // All timed task entries.
    26  	logger    glog.ILogger    // Logger, it is nil in default.
    27  	jobWaiter sync.WaitGroup  // Graceful shutdown when cron jobs are stopped.
    28  }
    29  
    30  // New returns a new Cron object with default settings.
    31  func New() *Cron {
    32  	return &Cron{
    33  		idGen:   gtype.NewInt64(),
    34  		status:  gtype.NewInt(StatusRunning),
    35  		entries: gmap.NewStrAnyMap(true),
    36  	}
    37  }
    38  
    39  // SetLogger sets the logger for cron.
    40  func (c *Cron) SetLogger(logger glog.ILogger) {
    41  	c.logger = logger
    42  }
    43  
    44  // GetLogger returns the logger in the cron.
    45  func (c *Cron) GetLogger() glog.ILogger {
    46  	return c.logger
    47  }
    48  
    49  // AddEntry creates and returns a new Entry object.
    50  func (c *Cron) AddEntry(
    51  	ctx context.Context,
    52  	pattern string,
    53  	job JobFunc,
    54  	times int,
    55  	isSingleton bool,
    56  	name ...string,
    57  ) (*Entry, error) {
    58  	var (
    59  		entryName = ""
    60  		infinite  = false
    61  	)
    62  	if len(name) > 0 {
    63  		entryName = name[0]
    64  	}
    65  	if times <= 0 {
    66  		infinite = true
    67  	}
    68  	return c.doAddEntry(doAddEntryInput{
    69  		Name:        entryName,
    70  		Job:         job,
    71  		Ctx:         ctx,
    72  		Times:       times,
    73  		Pattern:     pattern,
    74  		IsSingleton: isSingleton,
    75  		Infinite:    infinite,
    76  	})
    77  }
    78  
    79  // Add adds a timed task.
    80  // A unique `name` can be bound with the timed task.
    81  // It returns and error if the `name` is already used.
    82  func (c *Cron) Add(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) {
    83  	return c.AddEntry(ctx, pattern, job, -1, false, name...)
    84  }
    85  
    86  // AddSingleton adds a singleton timed task.
    87  // A singleton timed task is that can only be running one single instance at the same time.
    88  // A unique `name` can be bound with the timed task.
    89  // It returns and error if the `name` is already used.
    90  func (c *Cron) AddSingleton(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) {
    91  	return c.AddEntry(ctx, pattern, job, -1, true, name...)
    92  }
    93  
    94  // AddTimes adds a timed task which can be run specified times.
    95  // A unique `name` can be bound with the timed task.
    96  // It returns and error if the `name` is already used.
    97  func (c *Cron) AddTimes(ctx context.Context, pattern string, times int, job JobFunc, name ...string) (*Entry, error) {
    98  	return c.AddEntry(ctx, pattern, job, times, false, name...)
    99  }
   100  
   101  // AddOnce adds a timed task which can be run only once.
   102  // A unique `name` can be bound with the timed task.
   103  // It returns and error if the `name` is already used.
   104  func (c *Cron) AddOnce(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) {
   105  	return c.AddEntry(ctx, pattern, job, 1, false, name...)
   106  }
   107  
   108  // DelayAddEntry adds a timed task after `delay` time.
   109  func (c *Cron) DelayAddEntry(ctx context.Context, delay time.Duration, pattern string, job JobFunc, times int, isSingleton bool, name ...string) {
   110  	gtimer.AddOnce(ctx, delay, func(ctx context.Context) {
   111  		if _, err := c.AddEntry(ctx, pattern, job, times, isSingleton, name...); err != nil {
   112  			panic(err)
   113  		}
   114  	})
   115  }
   116  
   117  // DelayAdd adds a timed task after `delay` time.
   118  func (c *Cron) DelayAdd(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) {
   119  	gtimer.AddOnce(ctx, delay, func(ctx context.Context) {
   120  		if _, err := c.Add(ctx, pattern, job, name...); err != nil {
   121  			panic(err)
   122  		}
   123  	})
   124  }
   125  
   126  // DelayAddSingleton adds a singleton timed task after `delay` time.
   127  func (c *Cron) DelayAddSingleton(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) {
   128  	gtimer.AddOnce(ctx, delay, func(ctx context.Context) {
   129  		if _, err := c.AddSingleton(ctx, pattern, job, name...); err != nil {
   130  			panic(err)
   131  		}
   132  	})
   133  }
   134  
   135  // DelayAddOnce adds a timed task after `delay` time.
   136  // This timed task can be run only once.
   137  func (c *Cron) DelayAddOnce(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) {
   138  	gtimer.AddOnce(ctx, delay, func(ctx context.Context) {
   139  		if _, err := c.AddOnce(ctx, pattern, job, name...); err != nil {
   140  			panic(err)
   141  		}
   142  	})
   143  }
   144  
   145  // DelayAddTimes adds a timed task after `delay` time.
   146  // This timed task can be run specified times.
   147  func (c *Cron) DelayAddTimes(ctx context.Context, delay time.Duration, pattern string, times int, job JobFunc, name ...string) {
   148  	gtimer.AddOnce(ctx, delay, func(ctx context.Context) {
   149  		if _, err := c.AddTimes(ctx, pattern, times, job, name...); err != nil {
   150  			panic(err)
   151  		}
   152  	})
   153  }
   154  
   155  // Search returns a scheduled task with the specified `name`.
   156  // It returns nil if not found.
   157  func (c *Cron) Search(name string) *Entry {
   158  	if v := c.entries.Get(name); v != nil {
   159  		return v.(*Entry)
   160  	}
   161  	return nil
   162  }
   163  
   164  // Start starts running the specified timed task named `name`.
   165  // If no`name` specified, it starts the entire cron.
   166  func (c *Cron) Start(name ...string) {
   167  	if len(name) > 0 {
   168  		for _, v := range name {
   169  			if entry := c.Search(v); entry != nil {
   170  				entry.Start()
   171  			}
   172  		}
   173  	} else {
   174  		c.status.Set(StatusReady)
   175  	}
   176  }
   177  
   178  // Stop stops running the specified timed task named `name`.
   179  // If no`name` specified, it stops the entire cron.
   180  func (c *Cron) Stop(name ...string) {
   181  	if len(name) > 0 {
   182  		for _, v := range name {
   183  			if entry := c.Search(v); entry != nil {
   184  				entry.Stop()
   185  			}
   186  		}
   187  	} else {
   188  		c.status.Set(StatusStopped)
   189  	}
   190  }
   191  
   192  // StopGracefully Blocks and waits all current running jobs done.
   193  func (c *Cron) StopGracefully() {
   194  	c.status.Set(StatusStopped)
   195  	c.jobWaiter.Wait()
   196  }
   197  
   198  // Remove deletes scheduled task which named `name`.
   199  func (c *Cron) Remove(name string) {
   200  	if v := c.entries.Get(name); v != nil {
   201  		v.(*Entry).Close()
   202  	}
   203  }
   204  
   205  // Close stops and closes current cron.
   206  func (c *Cron) Close() {
   207  	c.status.Set(StatusClosed)
   208  }
   209  
   210  // Size returns the size of the timed tasks.
   211  func (c *Cron) Size() int {
   212  	return c.entries.Size()
   213  }
   214  
   215  // Entries return all timed tasks as slice(order by registered time asc).
   216  func (c *Cron) Entries() []*Entry {
   217  	array := garray.NewSortedArraySize(c.entries.Size(), func(v1, v2 interface{}) int {
   218  		entry1 := v1.(*Entry)
   219  		entry2 := v2.(*Entry)
   220  		if entry1.RegisterTime.Nanosecond() > entry2.RegisterTime.Nanosecond() {
   221  			return 1
   222  		}
   223  		return -1
   224  	}, true)
   225  	c.entries.RLockFunc(func(m map[string]interface{}) {
   226  		for _, v := range m {
   227  			array.Add(v.(*Entry))
   228  		}
   229  	})
   230  	entries := make([]*Entry, array.Len())
   231  	array.RLockFunc(func(array []interface{}) {
   232  		for k, v := range array {
   233  			entries[k] = v.(*Entry)
   234  		}
   235  	})
   236  	return entries
   237  }