Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Middle: питання на співбесіді з теми «Планувальник»

Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.

3 питання

Планувальник дозволяє описати періодичні завдання прямо в коді. У Laravel 11+ розклад визначається в routes/console.php через фасад Schedule:

use Illuminate\Support\Facades\Schedule;

Schedule::command('reports:send')->dailyAt('08:00');
Schedule::job(new PruneLogs)->weekly();
Schedule::call(fn () => Cache::flush())->hourly();

На сервері потрібен лише один cron-запис, що щохвилини викликає планувальник:

* * * * * cd /app && php artisan schedule:run >> /dev/null 2>&1

Корисні модифікатори: withoutOverlapping(), onOneServer(), runInBackground().

Докладніше в документації: Планувальник завдань

Розклад описують у routes/console.php ланцюжком методів:

Schedule::command('reports:send')
    ->weekdays()
    ->at('9:00')
    ->timezone('Europe/Kyiv');

Schedule::command('cache:prune-stale-tags')->hourly();
Schedule::job(new SyncRates)->everyFifteenMinutes()->between('8:00', '20:00');
Schedule::command('backup:run')->dailyAt('3:30')->environments(['production']);
Schedule::command('invoices:remind')->daily()->when(fn () => Setting::get('reminders_on'));

Групи методів:

  • частота: everyMinute(), everyFiveMinutes(), hourly(), daily(), weekly(), monthlyOn(1, '8:00'), cron('0 */6 * * *'); навіть everySecond();
  • дні: weekdays(), weekends(), mondays(), days([1, 3]);
  • час: between(), unlessBetween();
  • умови: when(), skip(), environments();
  • пояс: timezone() для завдання чи schedule_timezone у config/app.php для всіх.

Пастка з поясом: якщо час сервера UTC, а бізнес у Києві, dailyAt('9:00') без поясу спрацює о 11 чи 12 за київським. З переходом на літній час завдання в проміжку 3:00-4:00 можуть пропуститися чи виконатися двічі - критичні запускають поза ним.

php artisan schedule:list показує, коли кожне завдання виконається наступного разу.

Докладніше в документації: Варіанти частоти розкладу

Дві проблеми: наступний запуск того самого завдання стартує, поки попереднє ще працює, і довге завдання затримує інші, заплановані на ту саму хвилину.

Накладання - withoutOverlapping():

Schedule::command('import:products')
    ->everyFiveMinutes()
    ->withoutOverlapping(30);   // блокування на 30 хв на випадок аварії

Поки попередній запуск триває, новий пропускається. Блокування живе в кеші: якщо процес упав, воно спаде за вказаний час (за замовчуванням - 24 години, тож розумний ліміт варто задати).

Затримка інших - runInBackground():

Schedule::command('analytics:report')->daily()->runInBackground();

Завдання на той самий час виконуються послідовно; фонове не змушує наступні чекати. Працює для command() і exec().

Кращий шлях для важкого - щоб планувальник лише ставив роботу в чергу:

Schedule::job(new ImportProducts)->everyFiveMinutes();

Тоді планувальник звільняється миттєво, а повтори, таймаути й паралельність бере на себе черга (ShouldBeUnique проти дублів).

На кількох серверах до цього додається onOneServer() - зі спільним кешем.

Докладніше в документації: Запобігання накладанню завдань