dukecity/command-scheduler-bundle
Symfony bundle to schedule console commands with cron expressions. Manage native and custom commands, backed by database storage and optional Doctrine migrations. Supports modern PHP/Symfony versions; see wiki for configuration, execution, and upgrade notes.
composer config extra.symfony.allow-contrib true
composer require dukecity/command-scheduler-bundle
php bin/console make:migration
php bin/console doctrine:migrations:migrate
php bin/console assets:install --symlink --relative public
config/packages/security.yaml):
access_control:
- { path: ^/command-scheduler, role: ROLE_ADMIN }
Schedule a command (e.g., app:send-emails) to run daily at midnight:
/command-scheduler/list.0 0 * * * in the Cron Expression field.Define Commands:
Ensure your Symfony console commands are registered (e.g., app:send-emails). The bundle auto-discovers them via Symfony’s CommandLoader.
Schedule via UI:
Use the /command-scheduler/list dashboard to:
*/5 * * * * for every 5 minutes).Programmatic Scheduling (Advanced):
Use the ScheduledCommandFactory service to create schedules programmatically:
use Dukecity\CommandSchedulerBundle\Factory\ScheduledCommandFactory;
public function __construct(private ScheduledCommandFactory $factory) {}
public function scheduleExampleCommand(): void
{
$scheduledCommand = $this->factory->create();
$scheduledCommand->setCommand('app:send-emails');
$scheduledCommand->setCronExpression('0 0 * * *');
$scheduledCommand->setEnabled(true);
$entityManager->persist($scheduledCommand);
$entityManager->flush();
}
Event-Driven Extensions:
Listen to bundle events (e.g., SchedulerCommandExecutedEvent, SchedulerCommandFailedEvent) to log or notify:
use Dukecity\CommandSchedulerBundle\Event\SchedulerCommandExecutedEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(event: SchedulerCommandExecutedEvent::class, method: 'onCommandExecuted')]
public function onCommandExecuted(SchedulerCommandExecutedEvent $event): void
{
// Custom logic (e.g., Slack notification)
}
Environment-Specific Scheduling:
Use different cron expressions for dev vs. prod environments by overriding the bundle config:
# config/packages/dukecity_command_scheduler.yaml
dukecity_command_scheduler:
cron_expressions:
app:send-emails: "%env(CRON_EXPRESSION)%" # e.g., "*/10 * * * *" in prod
Custom Command Arguments:
Pass arguments to scheduled commands via the arguments field in the UI or programmatically:
$scheduledCommand->setArguments(['--limit=100']);
Logging and Monitoring:
Extend the BaseScheduledCommand entity to add custom fields (e.g., lastExecutionLog) for tracking:
#[ORM\Column(type: 'text', nullable: true)]
private ?string $lastExecutionLog = null;
Testing:
Use the SchedulerCommandTestTrait (if available) or mock the ScheduledCommandRepository in tests:
$this->entityManager->remove($scheduledCommand);
$this->entityManager->flush();
Cron Expression Syntax:
0 0 * *) will throw errors. Validate with tools like crontab.guru.CronExpression component, which may behave differently than Unix cron.Command Discovery:
Database Schema:
BaseScheduledCommand. Forgetting this will cause runtime errors.Permissions:
/command-scheduler route is not secured by default. Always restrict access (e.g., ROLE_ADMIN) as shown in the setup.Time Zones:
TZ environment variables or configure Symfony’s timezone if needed:
framework:
timezone: Europe/Berlin
Check Logs:
var/log/dev.log (or prod.log). Look for SchedulerCommandFailedEvent.Enable Debug Mode:
APP_DEBUG=1 to see detailed errors in the UI or CLI.Validate Entities:
$errors = $validator->validate($scheduledCommand);
if (count($errors) > 0) {
// Handle validation errors
}
Clear Cache:
ScheduledCommand entity, clear the cache:
php bin/console cache:clear
Custom Entity Fields:
BaseScheduledCommand to add metadata (e.g., priority, teamId). Example:
#[ORM\Column(type: 'integer')]
private int $priority = 0;
Override Templates:
vendor/dukecity/command-scheduler-bundle/Resources/views/) by copying them to templates/dukecity_command_scheduler/ and modifying.Event Listeners:
SchedulerCommandCreatedEvent to trigger side effects (e.g., send notifications):
#[AsEventListener(SchedulerCommandCreatedEvent::class)]
public function onCommandCreated(SchedulerCommandCreatedEvent $event): void
{
// Send email/Slack alert
}
Custom Command Loader:
dukecity_command_scheduler:
command_loader: App\Service\CustomCommandLoader
Bulk Scheduling:
Use the ScheduledCommandFactory in a loop to create multiple schedules:
foreach ($commands as $command) {
$scheduledCommand = $this->factory->create();
$scheduledCommand->setCommand($command['name']);
$scheduledCommand->setCronExpression($command['cron']);
// ...
}
Dynamic Cron Expressions: Fetch cron expressions from a config file or API:
# config/packages/dukecity_command_scheduler.yaml
dukecity_command_scheduler:
cron_expressions:
app:backup: "%env(BACKUP_CRON)%"
Rate Limiting:
Combine with Symfony’s RateLimiter to prevent overloading:
use Symfony\Component\RateLimiter\RateLimiterFactory;
$rateLimiter = RateLimiterFactory::create($container->getParameter('rate_limiter.token_bucket'));
if (!$rateLimiter->consume($tokenBucket)->isAllowed()) {
throw new \RuntimeException('Rate limit exceeded');
}
Docker/Serverless:
For serverless environments (e.g., AWS Lambda), use the executeImmediately endpoint to trigger commands on-demand:
curl -X POST /command-scheduler/detail/executeImmediately/{id}
How can I help you explore Laravel packages today?