Skip to main content
Version: CANARY 🚧

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.

About the Scheduler

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:

MethodDescription
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:

app/Kernel.php
<?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
}
Centralized configuration

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();
Queue

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​

MethodDescription
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​

MethodDescription
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​

MethodDescription
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​

MethodDescription
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​

MethodDescription
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
Caution

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​

/etc/supervisor/conf.d/bow-scheduler.conf
[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​

/etc/systemd/system/bow-scheduler.service
[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​

docker-compose.yml
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:

app/Kernel.php
<?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.