dbh/symfony-schedule-bundle
Installation
composer require dbh/symfony-schedule-bundle
Ensure Dbh\Symfony\ScheduleBundle\DbhScheduleBundle is enabled in config/bundles.php.
Create a Schedule Manager
Implement ManagerInterface in src/Model/ScheduleManager.php:
namespace App\Model;
use Dbh\Symfony\ScheduleBundle\Model\ManagerInterface;
use Dbh\Symfony\ScheduleBundle\Model\Schedule;
class ScheduleManager implements ManagerInterface {
public function schedule(Schedule $schedule) {
// Define your cron jobs here
}
}
Configure the Bundle
Create config/packages/schedule.yaml:
schedule:
manager: App\Model\ScheduleManager
Define a Command
Create a console command (e.g., src/Command/TestCommand.php) and reference it in schedule():
$schedule->command('app:test-command')->dailyAt('12:00');
Run the Scheduler Add a cron entry in your server to execute:
* * * * * php /path/to/bin/console schedule:run
Defining Jobs
Use the Schedule class to define cron jobs with Laravel-inspired syntax:
$schedule->command('app:backup')->daily();
$schedule->command('app:cleanup')->weeklyOn(1, '03:00'); // Every Monday at 3 AM
$schedule->command('app:report')->cron('0 9 * * 1-5'); // Custom cron expression
Chaining Methods Chain methods for readability:
$schedule->command('app:send-reminders')
->at('08:00')
->onWeekdays();
Environment-Specific Scheduling Use Symfony’s environment-aware services to conditionally schedule jobs:
if ($this->get('kernel')->getEnvironment() === 'prod') {
$schedule->command('app:monitor')->everyFiveMinutes();
}
Dynamic Scheduling
Inject dependencies (e.g., services) into ScheduleManager to dynamically configure jobs:
public function __construct(private SomeService $service) {}
public function schedule(Schedule $schedule) {
$schedule->command('app:process-' . $this->service->getQueue())
->hourly();
}
Logging and Monitoring
Extend ScheduleManager to log job executions or integrate with Symfony’s Monolog:
use Psr\Log\LoggerInterface;
public function __construct(private LoggerInterface $logger) {}
public function schedule(Schedule $schedule) {
$schedule->command('app:log-test')->daily();
// Log job registration
$this->logger->info('Scheduled log-test command daily');
}
Testing Schedules
Mock Schedule in PHPUnit tests to verify job configurations:
$schedule = $this->createMock(Schedule::class);
$manager = new ScheduleManager();
$manager->schedule($schedule);
$this->assertEquals('app:test-command', $schedule->expects()->command('app:test-command'));
Cron Syntax Errors
cron('0 9 * * *') with invalid time) may cause silent failures.CronExpression.Missing schedule:run Command
schedule:run will prevent jobs from triggering.* * * * * cd /path/to/project && php bin/console schedule:run >> /dev/null 2>&1
Command Not Found
app:nonexistent) throws an error during schedule:run.config/services.yaml or autoloaded.Timezone Mismatches
ScheduleManager:
DateTime::setTimezone(new DateTimeZone('Europe/Warsaw'));
Overwriting Configurations
schedule.yaml files or bundle overrides may conflict.imports in config/packages/schedule.yaml to merge configurations:
imports:
- { resource: schedule/local.yaml }
- { resource: schedule/prod.yaml }
Use Descriptive Command Names
Prefix commands with a namespace (e.g., app:backup-database) to avoid conflicts and improve clarity.
Leverage Symfony’s Dependency Injection
Inject services into ScheduleManager to dynamically fetch job configurations:
public function schedule(Schedule $schedule) {
$config = $this->configService->get('schedule');
foreach ($config['jobs'] as $job) {
$schedule->command($job['command'])->{$job['frequency']}();
}
}
Extend Schedule Class
Add custom methods to Schedule for project-specific needs (e.g., everyBusinessHour()):
// In a custom Schedule class
public function everyBusinessHour() {
return $this->cron('0 9-17 * * 1-5'); // 9 AM to 5 PM, Mon-Fri
}
Debugging Job Execution
Use Symfony’s debug:schedule command (if available) or log job triggers:
$schedule->command('app:debug')->dailyAt('00:00')->description('Debug logs');
Handle Job Failures Implement retry logic or notifications in commands. Example:
// In app/Command/TestCommand.php
protected function execute(InputInterface $input, OutputInterface $output) {
try {
// Job logic
} catch (\Exception $e) {
$this->logger->error('Job failed', ['error' => $e->getMessage()]);
throw $e; // Let Symfony handle it or add custom logic
}
}
Environment-Specific Schedules
Use Symfony’s %kernel.environment% parameter to load different schedules:
# config/packages/schedule.yaml
schedule:
manager: App\Model\ScheduleManager
environment: '%kernel.environment%'
Then conditionally load jobs in ScheduleManager:
if ($this->environment === 'prod') {
$schedule->command('app:prod-task')->hourly();
}
Avoid Hardcoding Paths
Use Symfony’s bin/console path (e.g., php bin/console) in cron entries instead of absolute paths to ensure portability.
Monitor Job Logs
Redirect schedule:run output to a log file for auditing:
* * * * * php bin/console schedule:run >> var/log/schedule.log 2>&1
How can I help you explore Laravel packages today?