mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 22:22:25 -05:00 
			
		
		
		
	
		
			
	
	
		
			100 lines
		
	
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			100 lines
		
	
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | package sched | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"time" | ||
|  | 
 | ||
|  | 	"codeberg.org/gruf/go-atomics" | ||
|  | ) | ||
|  | 
 | ||
|  | // Job encapsulates logic for a scheduled job to be run according | ||
|  | // to a set Timing, executing the job with a set panic handler, and | ||
|  | // holding onto a next execution time safely in a concurrent environment. | ||
|  | type Job struct { | ||
|  | 	id     uint64 | ||
|  | 	next   atomics.Time | ||
|  | 	timing Timing | ||
|  | 	call   func(time.Time) | ||
|  | 	panic  func(interface{}) | ||
|  | } | ||
|  | 
 | ||
|  | // NewJob returns a new Job to run given function. | ||
|  | func NewJob(fn func(now time.Time)) *Job { | ||
|  | 	if fn == nil { | ||
|  | 		// Ensure a function | ||
|  | 		panic("nil func") | ||
|  | 	} | ||
|  | 
 | ||
|  | 	j := &Job{ // set defaults | ||
|  | 		timing: emptytiming, // i.e. fire immediately | ||
|  | 		call:   fn, | ||
|  | 		panic:  func(i interface{}) { panic(i) }, | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// Init next time ptr | ||
|  | 	j.next.Store(zerotime) | ||
|  | 
 | ||
|  | 	return j | ||
|  | } | ||
|  | 
 | ||
|  | // At sets this Job to execute at time, by passing (*sched.Once)(&at) to .With(). See .With() for details. | ||
|  | func (job *Job) At(at time.Time) *Job { | ||
|  | 	return job.With((*Once)(&at)) | ||
|  | } | ||
|  | 
 | ||
|  | // Every sets this Job to execute every period, by passing sched.Period(period) to .With(). See .With() for details. | ||
|  | func (job *Job) Every(period time.Duration) *Job { | ||
|  | 	return job.With(Periodic(period)) | ||
|  | } | ||
|  | 
 | ||
|  | // EveryAt sets this Job to execute every period starting at time, by passing &PeriodicAt{once: Once(at), period: Periodic(period)} to .With(). See .With() for details. | ||
|  | func (job *Job) EveryAt(at time.Time, period time.Duration) *Job { | ||
|  | 	return job.With(&PeriodicAt{Once: Once(at), Period: Periodic(period)}) | ||
|  | } | ||
|  | 
 | ||
|  | // With sets this Job's timing to given implementation, or if already set will wrap existing using sched.TimingWrap{}. | ||
|  | func (job *Job) With(t Timing) *Job { | ||
|  | 	if t == nil { | ||
|  | 		// Ensure a timing | ||
|  | 		panic("nil Timing") | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if job.timing == emptytiming { | ||
|  | 		// Set new timing | ||
|  | 		job.timing = t | ||
|  | 	} else { | ||
|  | 		// Wrap old timing | ||
|  | 		old := job.timing | ||
|  | 		job.timing = &TimingWrap{ | ||
|  | 			Outer: t, | ||
|  | 			Inner: old, | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return job | ||
|  | } | ||
|  | 
 | ||
|  | // Panic specifics how this job handles panics, default is an actual panic. | ||
|  | func (job *Job) Panic(fn func(interface{})) *Job { | ||
|  | 	if fn == nil { | ||
|  | 		// Ensure a function | ||
|  | 		panic("nil func") | ||
|  | 	} | ||
|  | 	job.panic = fn | ||
|  | 	return job | ||
|  | } | ||
|  | 
 | ||
|  | // Next returns the next time this Job is expected to run. | ||
|  | func (job *Job) Next() time.Time { | ||
|  | 	return job.next.Load() | ||
|  | } | ||
|  | 
 | ||
|  | // Run will execute this Job and pass through given now time. | ||
|  | func (job *Job) Run(now time.Time) { | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			job.panic(r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 	job.call(now) | ||
|  | } |