Skip to main content
Winter Boot’s scheduling system lets you declare recurring tasks directly on service or component bean methods using the #[Scheduled] attribute. Rather than managing cron jobs externally, you embed timing logic inside your application code, and the framework handles process lifecycle and execution. Scheduled tasks run inside a dedicated worker process separate from the HTTP workers — this means a slow or long-running task never blocks web request handling. All you need is the Swoole extension and a single annotation on your application class to activate the feature.

Prerequisites

Scheduling is powered by the Swoole PHP extension. Install and enable it before using #[Scheduled].
1

Install the Swoole extension

2

Enable Swoole in php.ini

Enable Scheduling on Your Application Class

Add #[EnableScheduling] to your #[WinterBootApplication] class. The framework validates at startup that #[WinterBootApplication] is also present and that Swoole is loaded — a TypeError or AnnotationException is raised if either condition is not met.
MyApplication.php

The #[Scheduled] Attribute

Place #[Scheduled] on any public, non-final, non-abstract, zero-argument void method on a #[Service] or #[Component] bean. You must supply exactly one of the interval parameters (fixedDelay or fixedRate); combining conflicting options throws an AnnotationException at boot.
All integer timing values must be positive. Passing zero or a negative number raises a ValueError at boot time.

Parameters

int
Seconds to wait after the previous execution completes before starting the next. Use this when you want to avoid overlapping runs and the task duration may vary.
string
Property placeholder (e.g. ${my.delay}) that resolves to the fixedDelay value from your application configuration.
int
Seconds between the start of successive executions, regardless of how long each run takes. Use this when you need a consistent heartbeat.
string
Property placeholder resolving to the fixedRate value from your application configuration.
int
Seconds to wait after application startup before the first execution fires.
string
Property placeholder resolving to the initialDelay value from your application configuration.

Fixed Delay vs. Fixed Rate

The two core scheduling modes behave differently when a task takes longer than its interval. Choose the one that matches your task’s requirements.
fixedDelay introduces a gap between the end of one execution and the start of the next. Use this when you want to avoid overlapping runs and the task duration may vary.
CacheWarmer.php
Timeline: [startup] → 10s delay → run → 60s delay → run → 60s delay → run → …

Externalise Timing with Property Placeholders

Timing values can be externalised to application.yml using the String variants of each parameter. This lets you adjust schedules per environment without redeploying code.
application.yml
SomeScheduler.php
Use property placeholders for delays in production-facing applications. You can tune scheduling intervals per environment (dev, staging, prod) via separate application.yml profiles without touching PHP source code.

Configuration

Configure the scheduling worker pool in application.yml under winter.task.scheduling:
application.yml
int
Total number of worker processes dedicated to executing scheduled tasks.
int
Maximum number of concurrent scheduled task invocations that can be queued at once.
Scheduled tasks run inside a separate worker process managed by Swoole. They are entirely non-blocking with respect to incoming HTTP requests — web workers and scheduling workers never share execution time.

Complete Example

The following files show a full scheduling setup: the application entry point and a scheduler component with two differently-timed tasks.