Installation:
composer require aurimasniekis/scheduler-bundle
Add to config/bundles.php:
AurimasNiekis\SchedulerBundle\AurimasNiekisSchedulerBundle::class => ['all' => true],
Cron Configuration: Add to your server’s crontab (runs every minute):
* * * * * /path/to/laravel/bin/console scheduler:run >> /dev/null 2>&1
First Job:
Create a job class in app/Jobs:
namespace App\Jobs;
use AurimasNiekis\SchedulerBundle\ScheduledJobInterface;
class SendDailyReport implements ScheduledJobInterface
{
public function __invoke(): void
{
// Your logic here (e.g., send email, process data)
\Log::info('Daily report sent!');
}
public function getSchedulerExpression(): string
{
return '0 9 * * *'; // Runs daily at 9 AM
}
}
Verify Jobs: Check registered jobs with:
php artisan scheduler:list
Job Registration:
ScheduledJobInterface (auto-registered via Symfony’s autoconfigure).NamedScheduledJobInterface for custom job names (e.g., for CLI execution).Cron Expressions:
* * * * * for every minute, 0 0 * * 0 for weekly Sundays).dragonmantank/cron-expression (included).Manual Execution:
php artisan scheduler:execute SendDailyReport
or for named jobs:
php artisan scheduler:execute named_job
Dependency Injection:
class SendReport implements ScheduledJobInterface {
public function __construct(private Mailer $mailer) {}
public function __invoke(): void {
$this->mailer->send(...);
}
// ...
}
Logging and Monitoring:
__invoke() (e.g., Log::info()).scheduler:list to debug next run times or missed executions.Laravel-Specific Adjustments:
config/bundles.php with Laravel’s config/app.php (if using Laravel):
'providers' => [
AurimasNiekis\SchedulerBundle\AurimasNiekisSchedulerBundle::class,
],
Artisan facade for commands:
use Illuminate\Support\Facades\Artisan;
Artisan::call('scheduler:run');
Environment-Specific Scheduling:
.env):
class SendReport implements ScheduledJobInterface {
public function getSchedulerExpression(): string {
return env('SCHEDULER_EXPRESSION', '0 9 * * *');
}
}
Job Chaining:
__invoke():
public function __invoke(): void {
Artisan::call('scheduler:execute BackupDatabase');
}
Testing:
$this->app->bind(ScheduledJobInterface::class, function () {
return $this->createMock(ScheduledJobInterface::class);
});
Cron Tab Misconfiguration:
crontab -l and */1 * * * * echo "test".Time Zone Issues:
DateTime::setTimezone() in jobs if needed:
$now = new DateTime('now', new DateTimeZone('America/New_York'));
Job Overlaps:
Lock):
use Illuminate\Contracts\Bus\QueueingDispatcher;
use Illuminate\Bus\PendingDispatch;
public function __invoke(): void {
if (app(QueueingDispatcher::class)->lockFor('send_report', now()->addMinutes(10))) {
// Execute logic
}
}
Dependency Injection Quirks:
$this->app->bind(ScheduledJobInterface::class, function ($app) {
return new SendReport($app->make(Mailer::class));
});
Outdated Package:
Check Job Execution:
* * * * * /path/to/laravel/bin/console scheduler:run >> /var/log/scheduler.log 2>&1
scheduler:list to verify next run times.Manual Testing:
php artisan scheduler:execute SendDailyReport
Logging:
__invoke():
\Log::debug('Job started', ['class' => static::class]);
try {
// Logic
} catch (\Throwable $e) {
\Log::error('Job failed', ['error' => $e->getMessage()]);
}
Expression Validation:
use Cron\CronExpression;
$expression = new CronExpression('*/5 * * * *');
if (!$expression->isValid()) {
throw new \RuntimeException('Invalid cron expression');
}
Custom Job Storage:
// Example: Add a `runs` table and log executions in __invoke().
Dynamic Expressions:
public function getSchedulerExpression(): string {
return config('scheduler.expressions.send_report');
}
Event Dispatching:
JobStarting, JobCompleted):
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class SendReport implements ScheduledJobInterface {
public function __construct(private EventDispatcherInterface $dispatcher) {}
public function __invoke(): void {
$this->dispatcher->dispatch(new JobStarting());
// Logic
$this->dispatcher->dispatch(new JobCompleted());
}
}
Retry Mechanism:
retry helper):
use Illuminate\Support\Facades\Retry;
public function __invoke(): void {
Retry::retry(3, function () {
// Logic that might fail
});
}
How can I help you explore Laravel packages today?