Design patterns in the code
- Static factories for messages.
SchedulerCommandFactoryandSchedulerEventFactorybuildCommandandEventobjects for the Scheduler domain and send or raise them throughBusUtility. Callers do not construct scheduler messages directly. - Flow controller.
SchedulerFlowControllerinherits fromFlowController. It owns the Scheduler domain on the command bus and forwards commands to aSchedulerManager. - Abstract base with an abstract hook.
SchedulerManagerimplements the shared scheduling logic. TheProcessEventmethod is abstract, so each project supplies its own event handling. - Typed keys. Job and subject values travel in
ParamsunderSchedulerKeys, which areParamKeyinstances built fromSchedulerKeyNames. - Static helpers.
SchedulerServiceandSchedulerUtilityhold stateless logic for validation, due-job detection, completion, and job creation. - Static lookup.
ServiceLocator(a dependency) provides the bus registry.SchedulerFlowControllerreads theEventBusthrough it.
Connections to dependencies
- Contracts.
Domain.Scheduleridentifies the domain.CoreParamKeys.StringValueis used by one factory method. The scheduler's event verbs live in theContractsnamespace. - Params.
ParamsandParamKey<T>carry the job and subject. Each command and event owns its ownParamsinstance. - FlowController. The base class registers
HandleCommandon theCommandBusfor the Scheduler domain duringInit. - Bus.
BusUtility.Senddelivers commands.BusUtility.Raisedelivers events.SchedulerFlowControllersubscribes to Data-domain events on theEventBus. - Update.
SchedulerFlowController.InitcallsUpdateCommandFactory.RegisterUpdatable, which places theSchedulerManagerin the update system. Each frame, the update system callsOnUpdate, which callsTick. - Application.
ApplicationConstants.PausedGameSpeedis used to skip ticks whenTime.timeScaleis zero or below.
Key concepts
- Job. The scheduler's record for one scheduled item (
SchedulerConstants.Job). It holds an ID, a delay, an interval, a repeat count, theConfig, and theParamsit was scheduled with. - Config. A struct with
Delay,Interval,RepeatCount, and optionalEventandCommandfields. The scheduler reads only the first three. - IScheduledJob. The interface a job payload implements. It exposes
JobMetaData,Execute, andSetJobID. - Interval and repeats. An interval greater than zero makes a job repeat. An interval of zero makes it run once, regardless of
RepeatCount. - Pause. A flag in
SchedulerManager. While it is set,Tickreturns without changing any job.
Data and event flow
Scheduling:
- A caller creates a job and calls a
SchedulerCommandFactorymethod. - The factory builds a
Commandfor the Scheduler domain and sends it throughBusUtility.Send. - The
CommandBuscallsSchedulerFlowController.HandleCommand, which callsSchedulerManager.ProcessCommand. HandleSchedulechecks the subject, reads the job'sConfig, and callsSchedulerService.ValidateSchedulerStruct.- If valid,
SchedulerUtilityassigns the next ID and creates aSchedulerConstants.Job. The job is added to thejobsdictionary.
Ticking:
- The update system calls
SchedulerManager.OnUpdate, which callsTick. Tickreturns early if paused, if time scale is at or below the paused speed, or if there are no jobs.SchedulerService.FindDueJobstakes a snapshot of the job IDs, subtractsTime.deltaTimefrom each job's delay, and collects the IDs whose delay is at or below zero.- For each due job, ExecuteJob decrements the repeat count, calls SetJobID, and then calls Execute.
- If
Executereturns true,SchedulerService.HandleJobCompletioneither removes the job or resets its delay to its interval.
Pause and resume:
- A pause or resume command sets or clears the paused flag in
SchedulerManager. SchedulerEventFactoryraisesPausedorResumedon theEventBusin the Scheduler domain.
Incoming events:
SchedulerFlowControllersubscribes to the Data domain on theEventBus.- Each Data event is passed to
SchedulerManager.ProcessEvent, which the project subclass implements.
Cancel:
CancelScheduledJobssends a Cancel command with theJobsubject.HandleCancelclears thejobsdictionary.
Timing rules
- Delay is counted down by
Time.deltaTimeon each tick that actually runs. A job whose delay is zero or less is due on that tick. - A job scheduled with a delay of zero runs on the first tick after it is scheduled.
- A repeating job with an interval greater than zero has its delay reset to the interval after each successful run.
- Repeat count is decremented before execution. A job is removed when its count falls below the threshold of 1, but only after a successful
Execute.
Failed execution: if Execute returns false, the repeat count is still decremented, the delay is not reset, and the job is not removed. Because the delay stays at or below zero, the job is due again on the next tick. The repeat count can then go below the threshold without removing the job, since removal only happens after a successful Execute.
Thread safety
The scheduler runs on the Unity main thread, so schedule, pause, resume and cancel jobs from the main thread only.