Installation
Run composer require colourstream/cron-bundle:dev-master and update dependencies.
Register the bundle in config/bundles.php (Symfony 3+) or ApplicationKernel.php (Symfony 2.x):
ColourStream\Bundle\CronBundle\ColourStreamCronBundle::class => ['all' => true],
Database Setup Update your schema:
php bin/console doctrine:schema:update --force
This creates the cron_job table to store scheduled tasks.
First Use Case: Register a Job
Define a command (e.g., app/Command/ExampleCommand.php):
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ExampleCommand extends Command
{
protected function configure()
{
$this->setName('app:example');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln('Running example job!');
}
}
Register it via YAML (config/packages/cron.yaml):
colourstream_cron:
jobs:
app_example:
command: 'app:example'
schedule: '0 0 * * *' # Runs daily at midnight
Trigger Jobs Scan for new jobs:
php bin/console cron:scan
Run pending jobs:
php bin/console cron:run
Job Registration
config/packages/cron.yaml under colourstream_cron.jobs.
colourstream_cron:
jobs:
cleanup_cache:
command: 'cache:clear'
schedule: '0 3 * * *' # Daily at 3 AM
description: 'Clear cache nightly'
CronManager service to register jobs programmatically:
$manager = $container->get('colourstream_cron.manager');
$manager->addJob('dynamic_job', 'app:dynamic', '0 0 * * *');
Running Jobs
cron:run to execute pending jobs.Router) to trigger jobs via HTTP:
// src/Controller/CronController.php
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class CronController
{
#[Route('/cron/run', name: 'cron_run')]
public function run(CronManager $manager): Response
{
$manager->runJobs();
return new Response('Jobs executed');
}
}
Configure a webcron service (e.g., Cron-job.org) to hit this endpoint.Logging and Monitoring
Logger to log job execution:
use Psr\Log\LoggerInterface;
class ExampleCommand extends Command
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->logger->info('Example job started');
// ...
}
}
cron_job table for execution history:
php bin/console doctrine:query:sql "SELECT * FROM cron_job WHERE command = 'app:example'"
Environment-Specific Scheduling Use Symfony’s environment variables or parameter bags to toggle jobs:
# config/packages/dev/cron.yaml
colourstream_cron:
jobs:
debug_logs:
command: 'app:debug-logs'
schedule: '*/5 * * * *' # Every 5 minutes (dev only)
Database Schema Mismatch
cron_job table (e.g., adding columns), run doctrine:schema:update before registering new jobs. Migrations are not handled automatically.Job Overlaps
Process to kill stale jobs:
use Symfony\Component\Process\Process;
$process = new Process(['php', 'bin/console', 'app:example']);
$process->start();
if (!$process->isRunning()) {
$this->logger->warning('Job already running, skipping');
return;
}
Cron Syntax Errors
0 0 * * missing a field) will silently fail during cron:scan.cron-expression or add a custom validator:
use Cron\CronExpression;
public function isValidSchedule(string $schedule): bool
{
try {
new CronExpression($schedule);
return true;
} catch (\Exception $e) {
return false;
}
}
Symfony 2.x Limitations
Idempotency Design commands to be idempotent (safe to rerun). Example:
// app/Command/SendReportCommand.php
protected function execute(InputInterface $input, OutputInterface $output)
{
$report = $this->reportRepository->findOneBy(['sent_at' => null]);
if (!$report) {
$output->writeln('No unsent reports found');
return;
}
// Send report logic...
}
Environment-Aware Scheduling
Use %kernel.environment% in schedules to disable jobs in production:
colourstream_cron:
jobs:
dev_only_job:
command: 'app:dev-task'
schedule: '%kernel.environment% == "dev" ? "*/1 * * * *" : ""'
Custom Job Metadata
Extend the cron_job table to store additional fields (e.g., priority, timeout):
php bin/console make:migration
Update the bundle’s CronJob entity or create a custom repository.
Testing Jobs
Mock the CronManager in PHPUnit tests:
use ColourStream\Bundle\CronBundle\Manager\CronManager;
$cronManager = $this->createMock(CronManager::class);
$cronManager->expects($this->once())
->method('runJobs')
->willReturn(true);
$this->container->set('colourstream_cron.manager', $cronManager);
Performance
For large-scale applications, batch jobs by priority or use a queue system (e.g., Symfony Messenger) to avoid long-running cron:run processes.
Webhook Security
If exposing a web endpoint for cron:run, add authentication:
#[Route('/cron/run', name: 'cron_run', methods: ['POST'])]
public function run(CronManager $manager, Request $request): Response
{
if (!$request->headers->get('X-Cron-Secret') === $this->getParameter('cron_secret')) {
throw $this->createAccessDeniedException();
}
$manager->runJobs();
return new Response('OK');
}
How can I help you explore Laravel packages today?