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