CLI · Winter Console

The schedule command

Scheduled tasks are not listed in one file — they are scattered through the code as #[Scheduled] attributes. The schedule command gathers them into a table, shows each one’s schedule and manages the scheduler itself.

Alias call schDefault listScheduler one per host

What is scheduled

The default action is the listing, so the command can be called with no arguments:

bash
php call schedule
php call sch list           # the same thing
text
[ Scheduled Tasks ]
TASK                                           TRIGGER
MainTaskDigest::sendDaily                    cron 0 9 * * *
MainTaskCleanup::purgeTemp                   fixedRate 3600s
MainTaskSync::pullRates                      fixedDelay 300s
- - - - - - - - - -
[i] 3 task(s) defined.

This is the only way to see the whole schedule: the attributes live next to their methods, and finding them by eye across a project gets harder the bigger it grows.

Trigger What it means
cron 0 9 * * * By the calendar — five fields, no seconds
fixedRate 3600s Every hour from the start of the previous run
fixedDelay 300s Five minutes after the previous run finished

The difference between the last two matters: fixedRate holds the frequency, fixedDelay holds the pause. In detail on the Scheduler page.

The listing does not need a running scheduler

list scans the project rather than asking a running process. So it always works — and it is the way to check the schedule before a deploy, or to confirm that a new task was picked up at all.

Starting the scheduler

bash
php call sch start        # in the terminal
php call sch start -d     # in the background
php call sch stop         # graceful stop

The scheduler is one long-lived process that watches the clock and starts tasks as their times arrive. It runs the tasks themselves separately, so a long task does not push everyone else’s schedule along.

One scheduler per host

A second start will not create a second scheduler: the class is protected by a lock, like any singleton process. That is protection against double firing — otherwise, after a failed deploy or a restart, tasks would run twice.

It follows that across several servers the scheduler must run on one of them. The application scales; the scheduler does not.

Usually it is not started separately: the #[EnableScheduler] attribute on the application class brings the scheduler up together with call run. A separate start is for when the scheduler lives as its own process — in its own container or under a supervisor.

Status

bash
php call sch status
text
[ Scheduler Status ]
Scheduler                  Scheduler ● RUNNING
- - - - - - - - - -
PID          52190
State        RUNNING
Activity     IDLE
Started      2026-08-14 06:40:12
Uptime       7h 55m
Tasks        3

Activity shows whether a task is running right now. IDLE means the scheduler is waiting for the next due time; that is the normal state almost all the time.

If the scheduler is stopped, the command says so plainly:

text
  Scheduler                  ○ STOPPED
[i] The scheduler is not running.

Every action

Command What it does
list Every task and its schedule (the default)
start Start in the terminal
start -d Start in the background
stop A graceful stop (SIGTERM)
status State, PID, uptime, task count

Next

  • Scheduler#[Scheduled], cron, fixedRate and fixedDelay
  • process — single processes
  • daemon — daemons and worker fleets
  • run — starting the scheduler together with the application