Senior: питання на співбесіді з теми «Artisan»
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
2 питання
Довгу команду переривають деплой, зупинка контейнера, OOM. Вона має завершуватися чисто й продовжувати, а не починати все з нуля чи дублювати роботу.
1. Реагувати на сигнал:
public function handle(): int
{
$this->trap([SIGTERM, SIGINT], fn () => $this->shouldStop = true);
Order::query()->where('synced', false)->lazyById(500)->each(function (Order $order) {
if ($this->shouldStop) {
return false; // вийти після поточного запису
}
$this->sync($order);
$order->update(['synced' => true]);
});
return self::SUCCESS;
}
2. Пам'ятати прогрес у даних, а не в пам'яті: позначка synced, останній оброблений id у таблиці чи кеші. Перезапуск продовжить з місця зупинки.
3. Ідемпотентність кроку: повторна обробка того самого запису не має шкодити - перевірка стану чи унікальний ключ.
4. Один екземпляр: Isolatable і --isolated або withoutOverlapping() у планувальнику.
5. Обходити дані порціями (lazyById, chunkById) - щоб пам'ять не росла, а зміни не зсували сторінки.
Альтернатива для дуже великих обсягів - команда лише розбиває роботу на завдання черги (батчі), а повтори й паралельність бере на себе черга.
Команду запускають cron, CI, скрипти деплою - не люди. Їй треба повідомляти результат так, щоб це зрозуміла машина.
Коди виходу: 0 - успіх, будь-що інше - збій. Скрипт деплою й CI зупиняються саме на ненульовому коді.
if ($failed > 0) {
$this->error("{$failed} записів не оброблено");
return self::FAILURE;
}
return self::SUCCESS;
// або з будь-якого місця
$this->fail('Немає підключення до API');
Команда, що ловить винятки й завжди повертає 0, приховує збої від усього навколо.
Інше, що варто мати:
- неінтерактивність: без
confirm()іask()у шляху виконання за розкладом; підтвердження руйнівних дій - через--forceі перевіркуisProduction(); - журнал, а не лише консоль:
$this->info()бачить лише той, хто дивиться в термінал; підсумок і помилки - ще й уLog; --dry-runдля команд, що змінюють дані, - показати, що буде змінено;- прогрес і підсумок (оброблено, пропущено, помилки) - щоб було видно, що команда не зависла;
- тести:
$this->artisan('reports:send', ['user' => 7])->assertSuccessful()->expectsOutputToContain('Надіслано').