Task Scheduler
Introductionβ
BowPHP's scheduler offers a simple and elegant way to define scheduled tasks. It lets you automate recurring tasks such as database backups, sending emails, cache clearing, and much more.
The scheduler uses cron expressions internally, but lets you define them with a fluent PHP API that is more readable and maintainable.
Main methodsβ
The scheduler provides four main methods to schedule different types of tasks:
| Method | Description |
|---|---|
command() | Runs Bow console commands |
task() | Runs QueueTask classes |
exec() | Runs shell/bash commands |
call() | Runs closures/callbacks |
Defining tasksβ
Scheduled tasks are defined in the schedules() method of your App\Kernel class. This approach offers better integration with the framework and centralized configuration:
<?php
namespace App;
use Bow\Scheduler\Scheduler;
use Bow\Configuration\Loader as ApplicationLoader;
class Kernel extends ApplicationLoader
{
/**
* Define your scheduled tasks
*
* @param Scheduler $schedule
* @return void
*/
public function schedules(Scheduler $schedule): void
{
// Schedule a Bow console command
$schedule->command('cache:clear')
->dailyAt('02:00')
->description('Clear the application cache');
// Schedule a shell command
$schedule->exec('mysqldump -u root mydb > /backups/db.sql')
->dailyAt('03:00')
->description('Back up the database')
->runInBackground();
// Schedule a closure
$schedule->call(function () {
logger('Cleanup task executed...');
})
->hourly()
->description('Cleanup task');
// Schedule a QueueTask on Sunday at 10:00
// (1 = Monday β¦ 7 = Sunday)
$schedule->task(App\Tasks\SendWeeklyReportTask::class)
->weeklyOn(7, '10:00')
->description('Send the weekly reports');
}
// ... other Kernel methods
}
The schedules() method is automatically called when the scheduler commands run. All your tasks are defined in the same place as your other application configurations.
Scheduling console commandsβ
The command() method lets you schedule a Bow console command:
// Simple command
$schedule->command('migration:migrate')->daily();
// Command with parameters
$schedule->command('email:send', ['--to' => 'admin@example.com'])->hourly();
// Command with description
$schedule->command('cache:clear')
->dailyAt('02:00')
->description('Clear the cache daily');
Scheduling QueueTaskβ
The task() method lets you schedule the execution of QueueTask classes:
// By class name
$schedule->task(App\Tasks\ProcessReportsTask::class)->daily();
// With constructor parameters
$schedule->task(App\Tasks\SendNotificationTask::class, ['user', 'message'])->hourly();
// With an instance
$task = new App\Tasks\GenerateStats($config);
$schedule->task($task)->weekly();
Scheduled QueueTasks are automatically pushed to the configured queue.
Specifying the queue connectionβ
You can specify which queue connection to use:
$schedule->task(App\Tasks\ProcessReportsTask::class)
->daily()
->onConnection('redis');
Scheduling shell commandsβ
The exec() method lets you run shell/bash commands:
// Simple command
$schedule->exec('rm -rf /tmp/cache/*')->dailyAt('04:00');
// With parameters (automatically escaped)
$schedule->exec('tar -czf backup.tar.gz', ['/var/www/files'])->weekly();
// In the background
$schedule->exec('php process-heavy-task.php')
->daily()
->runInBackground();
Scheduling closuresβ
The call() method lets you run closures or callbacks:
// Simple closure
$schedule->call(function () {
// Your code here
})->everyFiveMinutes();
// With parameters
$schedule->call(function ($name, $email) {
logger("Processing: {$name} ({$email})");
}, ['John', 'john@example.com'])->hourly();
Scheduling frequenciesβ
The scheduler provides many methods to define the execution frequency:
Minute intervalsβ
| Method | Description |
|---|---|
everyMinute() | Run every minute |
everyTwoMinutes() | Run every 2 minutes |
everyFiveMinutes() | Run every 5 minutes |
everyTenMinutes() | Run every 10 minutes |
everyFifteenMinutes() | Run every 15 minutes |
everyThirtyMinutes() | Run every 30 minutes |
Hour intervalsβ
| Method | Description |
|---|---|
hourly() | Run every hour |
hourlyAt(17) | Run every hour at minute 17 |
everyTwoHours() | Run every 2 hours |
everyThreeHours() | Run every 3 hours |
everyFourHours() | Run every 4 hours |
everySixHours() | Run every 6 hours |
Daily and weekly intervalsβ
| Method | Description |
|---|---|
daily() | Run daily at midnight |
dailyAt('13:00') | Run daily at 13:00 |
twiceDaily(1, 13) | Run daily at 1:00 and 13:00 |
weekly() | Run weekly on Sunday |
weeklyOn(1, '8:00') | Run weekly on Monday at 8:00 |
Monthly and yearly intervalsβ
| Method | Description |
|---|---|
monthly() | Run monthly on the 1st at midnight |
monthlyOn(15, '15:00') | Run monthly on the 15th at 15:00 |
twiceMonthly(1, 16, '13:00') | Run twice a month |
quarterly() | Run quarterly |
yearly() | Run yearly |
yearlyOn(6, 1, '17:00') | Run on June 1st at 17:00 |
Specific timeβ
To set the time for a recurring execution, use the *At variant
corresponding to the frequency β there is no standalone chainable
at() method.
$schedule->command('report:generate')->dailyAt('09:00');
$schedule->command('report:generate')->hourlyAt(15); // every hour at hh:15
$schedule->command('report:generate')->weeklyOn(1, '08:00'); // Monday 8:00
$schedule->command('report:generate')->monthlyOn(15, '15:00'); // the 15th at 15:00
$schedule->command('report:generate')->yearlyOn(6, 1, '17:00'); // June 1st 17:00
Custom cron expressionβ
If you need a more complex expression, use the cron() method:
$schedule->command('custom:task')
->cron('0 */4 * * 1-5'); // Every 4 hours, Monday to Friday
Day constraintsβ
You can restrict execution to specific days:
// Weekdays only
$schedule->command('report:generate')
->daily()
->weekdays();
// Weekend only
$schedule->command('cleanup')
->daily()
->weekends();
// Specific days
$schedule->command('backup')
->daily()
->mondays();
$schedule->command('reports')
->daily()
->fridays();
Available day methodsβ
| Method | Description |
|---|---|
mondays() | Monday only |
tuesdays() | Tuesday only |
wednesdays() | Wednesday only |
thursdays() | Thursday only |
fridays() | Friday only |
saturdays() | Saturday only |
sundays() | Sunday only |
weekdays() | Monday to Friday |
weekends() | Saturday and Sunday |
days(1, 3, 5) | Custom days (Monday, Wednesday, Friday) |
Advanced optionsβ
Background executionβ
For long-running commands, run them in the background:
$schedule->exec('php process-heavy-task.php')
->daily()
->runInBackground();
Preventing overlapsβ
Prevent a scheduled task from running if a previous instance is still in progress:
$schedule->command('slow:process')
->hourly()
->withoutOverlapping(60); // The lock expires after 60 minutes
Make sure the cache is configured so that overlap prevention works correctly.
Conditional schedulingβ
Run tasks only when certain conditions are met:
// Run only if the condition is true
$schedule->command('send:emails')
->daily()
->when(function () {
return app()->environment('production');
});
// Skip if the condition is true
$schedule->command('debug:task')
->daily()
->skip(function () {
return app()->environment('production');
});
Timezoneβ
Set a specific timezone for the schedule:
$schedule->command('report:generate')
->dailyAt('09:00')
->timezone('Europe/Paris');
Descriptionβ
Add a description to easily identify your tasks:
$schedule->command('cache:clear')
->daily()
->description('Clear the cache daily');
Console commandsβ
Run due tasksβ
Runs all tasks that are due:
php bow schedule:run
Start the scheduler daemonβ
Starts the scheduler in continuous mode (recommended in production):
php bow schedule:work
List scheduled tasksβ
Displays all registered scheduled tasks:
php bow schedule:list
Show the next executionsβ
Displays when each task will next run:
php bow schedule:next
Test a taskβ
Manually runs a scheduled task by its fully qualified class name:
php bow schedule:test App\\Tasks\\SendWeeklyReportTask
Production configurationβ
Cronβ
Add this cron entry to run the scheduler every minute:
* * * * * cd /var/www/bow-app && php bow schedule:run >> /var/log/bow-scheduler.log 2>&1
Supervisorβ
[program:bow-scheduler]
directory=/var/www/bow-app
command=php bow schedule:work
autostart=true
autorestart=true
user=www-data
stdout_logfile=/var/log/bow-scheduler.log
sudo supervisorctl reread && sudo supervisorctl update && sudo supervisorctl start bow-scheduler
systemdβ
[Unit]
Description=Bow Scheduler
After=network.target
[Service]
User=www-data
WorkingDirectory=/var/www/bow-app
ExecStart=/usr/bin/php bow schedule:work
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && sudo systemctl enable bow-scheduler && sudo systemctl start bow-scheduler
Dockerβ
services:
scheduler:
build: .
command: php bow schedule:work
restart: unless-stopped
volumes:
- .:/var/www/html
depends_on:
- mysql
Complete exampleβ
Here is a complete example of configuring the scheduler in the Kernel:
<?php
namespace App;
use Bow\Scheduler\Scheduler;
use Bow\Configuration\Loader as ApplicationLoader;
class Kernel extends ApplicationLoader
{
public function schedules(Scheduler $schedule): void
{
// Daily database backup (1:00)
$schedule->exec('mysqldump mydb > /backups/daily.sql')
->dailyAt('01:00')
->description('Daily database backup')
->runInBackground();
// Clear the cache every Sunday at 2:00 (1 = Monday, 7 = Sunday)
$schedule->command('cache:clear')
->weeklyOn(7, '02:00')
->description('Weekly cache cleanup');
// Process pending reports every hour
$schedule->task(\App\Tasks\ProcessPendingReportsTask::class)
->hourly()
->withoutOverlapping()
->description('Process pending reports');
// Check the system health every 5 minutes
$schedule->call(function () {
$health = \App\Services\HealthChecker::check();
if (!$health->isHealthy()) {
\App\Services\AlertService::notify($health);
}
})
->everyFiveMinutes()
->description('System health check');
// Send the weekly reports on Friday at 17:00 (production only)
$schedule->task(\App\Tasks\SendWeeklyReportTask::class)
->weeklyOn(5, '17:00')
->timezone('Europe/Paris')
->when(function () {
return app()->environment('production');
})
->description('Send the weekly reports');
}
// ... other methods
}
Is something missing?
If you run into problems with the documentation or have suggestions to improve the documentation or the project in general, please open an issue for us, or send a tweet mentioning the Twitter account @bowframework or directly on github.