2022-07-10 16:18:21 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								package  sched  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
									
										
										
										
											2022-07-22 11:43:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"reflect" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"strconv" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"strings" 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-26 19:23:41 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"sync/atomic" 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-10 16:18:21 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"time" 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-26 19:23:41 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"unsafe" 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-10 16:18:21 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 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 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-26 19:23:41 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									next    unsafe . Pointer  // *time.Time 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-10 16:18:21 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									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 )  } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									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" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-09-28 18:30:40 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  job . id  !=  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Cannot update scheduled job 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										panic ( "job already scheduled" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-07-10 16:18:21 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									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 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-09-28 18:30:40 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// OnPanic specifies how this job handles panics, default is an actual panic.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( job  * Job )  OnPanic ( fn  func ( interface { } ) )  * Job  {  
						 
					
						
							
								
									
										
										
										
											2022-07-10 16:18:21 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  fn  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Ensure a function 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										panic ( "nil func" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-28 18:30:40 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  job . id  !=  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Cannot update scheduled job 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										panic ( "job already scheduled" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-07-10 16:18:21 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									job . panic  =  fn 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  job 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Next returns the next time this Job is expected to run.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( job  * Job )  Next ( )  time . Time  {  
						 
					
						
							
								
									
										
										
										
											2024-09-26 19:23:41 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  loadTime ( & job . next ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-10 16:18:21 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Run will execute this Job and pass through given now time.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( job  * Job )  Run ( now  time . Time )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-26 19:23:41 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										switch  r  :=  recover ( ) ;  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  r  ==  nil : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// no panic 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  job  !=  nil  && 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											job . panic  !=  nil : 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-10 16:18:21 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											job . panic ( r ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-26 19:23:41 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											panic ( r ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-10 16:18:21 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									job . call ( now ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2022-07-22 11:43:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// String provides a debuggable string representation of Job including ID, next time and Timing type.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( job  * Job )  String ( )  string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  buf  strings . Builder 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf . WriteByte ( '{' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf . WriteString ( "id=" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf . WriteString ( strconv . FormatUint ( job . id ,  10 ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf . WriteByte ( ' ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf . WriteString ( "next=" ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-26 19:23:41 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									buf . WriteString ( loadTime ( & job . next ) . Format ( time . StampMicro ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-22 11:43:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									buf . WriteByte ( ' ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf . WriteString ( "timing=" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf . WriteString ( reflect . TypeOf ( job . timing ) . String ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf . WriteByte ( '}' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  buf . String ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2024-09-26 19:23:41 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  loadTime ( p  * unsafe . Pointer )  time . Time  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  p  :=  atomic . LoadPointer ( p ) ;  p  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  * ( * time . Time ) ( p ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  zerotime 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  storeTime ( p  * unsafe . Pointer ,  t  time . Time )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									atomic . StorePointer ( p ,  unsafe . Pointer ( & t ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}