func (js *JobScheduler) RunLoop() {
	ctx := js.withBaseContext(js.Background())

	js.Latch.Started()
	defer func() {
		js.Latch.Stopped()
		js.Latch.Reset()
	}()

	if js.JobSchedule != nil {
		js.NextRuntime = js.JobSchedule.Next(js.NextRuntime)
	}

	// if the schedule returns a zero timestamp
	// it should be interpretted as *not* to automatically
	// schedule the job to be run.
	// The run loop will return and the job scheduler will be interpretted as stopped.
	if js.NextRuntime.IsZero() {
		return
	}

	for {
		if js.NextRuntime.IsZero() {
			return
		}

		runAt := time.After(js.NextRuntime.UTC().Sub(Now()))
		select {
		case <-runAt:
			if js.CanBeScheduled() {
				if _, _, err := js.RunAsyncContext(ctx); err != nil {
					_ = js.error(ctx, err)
				}
			}

			// set up the next runtime.
			if js.JobSchedule != nil {
				js.NextRuntime = js.JobSchedule.Next(js.NextRuntime)
			} else {
				js.NextRuntime = Zero
			}

		case <-js.Latch.NotifyStopping():
			// note: we bail hard here
			// because the job executions in flight are
			// handled by the context cancellation.
			return
		}
	}
}
// RunLoop is the main scheduler loop.
// This call blocks.
// It alarms on the next runtime and forks a new routine to run the job.
// It can be aborted with the scheduler's async.Latch, or calling `.Stop()`.
// If this function exits for any reason, it will mark the scheduler as stopped.
RunLoop is the main scheduler loop.
This call blocks.
It alarms on the next runtime and forks a new routine to run the job.
It can be aborted with the scheduler's async.Latch, or calling `.Stop()`.
If this function exits for any reason, it will mark the scheduler as stopped.
// RunLoop is the main scheduler loop . // This call blocks . // It alarms on the next runtime and forks a new routine to run the job . // It can be aborted with the scheduler ' s async . Latch or calling ` . Stop () ` . // If this function exits for any reason it will mark the scheduler as stopped .
func (js *JobScheduler) RunLoop() {
	ctx := js.withBaseContext(js.Background())
	js.Latch.Started()
	defer func() {
		js.Latch.Stopped()
		js.Latch.Reset()
	}()
	if js.JobSchedule != nil {
		js.NextRuntime = js.JobSchedule.Next(js.NextRuntime)
	}
	if js.NextRuntime.IsZero() {
		return
	}
	for {
		if js.NextRuntime.IsZero() {
			return
		}
		runAt := time.After(js.NextRuntime.UTC().Sub(Now()))
		select {
		case <-runAt:
			if js.CanBeScheduled() {
				if _, _, err := js.RunAsyncContext(ctx); err != nil {
					_ = js.error(ctx, err)
				}
			}
			if js.JobSchedule != nil {
				js.NextRuntime = js.JobSchedule.Next(js.NextRuntime)
			} else {
				js.NextRuntime = Zero
			}
		case <-js.Latch.NotifyStopping():
			return
		}
	}
}
func ( js * JobScheduler ) RunLoop ( ) { ctx := js . withBaseContext ( js . Background ( ) ) js . Latch . Started ( ) defer func ( ) { js . Latch . Stopped ( ) js . Latch . Reset ( ) } ( ) if js . JobSchedule != nil { js . NextRuntime = js . JobSchedule . Next ( js . NextRuntime ) } if js . NextRuntime . IsZero ( ) { return } for { if js . NextRuntime . IsZero ( ) { return } runAt := time . After ( js . NextRuntime . UTC ( ) . Sub ( Now ( ) ) ) select { case <- runAt : if js . CanBeScheduled ( ) { if _ , _ , err := js . RunAsyncContext ( ctx ) ; err != nil { _ = js . error ( ctx , err ) } } if js . JobSchedule != nil { js . NextRuntime = js . JobSchedule . Next ( js . NextRuntime ) } else { js . NextRuntime = Zero } case <- js . Latch . NotifyStopping ( ) : return } } }
RunLoop is the main scheduler loop.
RunLoop is the main scheduler loop .
// if the schedule returns a zero timestamp // it should be interpretted as *not* to automatically // schedule the job to be run. // The run loop will return and the job scheduler will be interpretted as stopped. // set up the next runtime. // note: we bail hard here // because the job executions in flight are // handled by the context cancellation.