ix
ix

informatix

EN version Porozmawiajmy o projekcie
Strona główna / Blog / Laravel Scheduler — cron, zadania cykliczne i kolejki [2026]
• 8 min czytania •

Laravel Scheduler — cron, zadania cykliczne i kolejki [2026]

Laravel Scheduler zamienia dziesiątki wpisów w cronie na jeden — zadania definiujesz w kodzie i widzisz w schedule:list. Wzorzec produkcyjny: scheduler decyduje kiedy, kolejka wykonuje jak. Bez withoutOverlapping zadania nakładają się i dublują dane.

Laravel Scheduler zamienia dziesiątki wpisów w cronie na jeden — zadania cykliczne definiujesz w kodzie PHP, wersjonujesz w repozytorium i widzisz w jednym miejscu (php artisan schedule:list). Ten poradnik pokazuje konfigurację od podstaw, wszystkie istotne metody (withoutOverlapping, onOneServer, runInBackground) i najczęstszą pułapkę: zadania schedulera, które powinny trafiać do kolejki, a wykonują się synchronicznie i blokują cron.

Najważniejsze: Najważniejsze — Scheduler uruchamia się jednym wpisem w cronie: * * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1. Właściwe zadania definiujesz w routes/console.php (Laravel 11+) albo app/Console/Kernel.php. Zasada produkcyjna: scheduler ma kolejkować pracę (Schedule::job() albo runInBackground()), nie wykonywać jej synchronicznie. Każde zadanie cykliczne zabezpieczaj withoutOverlapping().

Jak działa Laravel Scheduler

Klasyczny cron wymaga wpisu per zadanie — pięć zadań to pięć linii w crontabie, rozsianych po serwerach i niespójnych między środowiskami. Laravel odwraca model: w cronie jest jeden wpis, który co minutę uruchamia schedule:run. Laravel sprawdza, które zadania mają się w tej minucie wykonać, i wykonuje je.

# crontab -e — jedyny wpis, jaki potrzebujesz
* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1

Zadania definiujesz w kodzie — w Laravelu 11+ w routes/console.php

use Illuminate\Support\Facades\Schedule;

Schedule::command('reports:daily')->dailyAt('06:00');
Schedule::command('invoices:sync')->everyFifteenMinutes();
Schedule::job(new SyncPrices)->hourly();
Schedule::call(fn () => Cache::forget('stats'))->daily();
  • Zalety tego modelu: definicje są wersjonowane razem z kodem, środowiska nie rozjeżdżają się, a podgląd całości to jedno polecenie php artisan schedule:list. W development można też uruchomić php artisan schedule:work — proces, który sam czeka na właściwą minutę, bez dotykania crona.

Scheduler + kolejki — wzorzec produkcyjny

Najważniejsza decyzja projektowa: co scheduler robi, a czego nie robi. Scheduler ma tylko zdecydować „teraz" i przekazać pracę do kolejki. Wykonywanie ciężkiej pracy bezpośrednio w schedulerze blokuje kolejne zadania crona — schedule:run czeka na zakończenie zadania, a kolejne minuty mijają.

// ŹLE — 5-minutowy raport blokuje cron na 5 minut
Schedule::command('reports:generate')->hourly();

// DOBRZE — komenda sama w sobie szybka, ciężka praca w kolejce
Schedule::job(new GenerateDailyReport)->hourly();

// DOBRZE — komenda uruchomiona w tle, cron nie czeka
Schedule::command('reports:generate')->hourly()->runInBackground();

Trzy warianty przekazania pracy do tła

  • Schedule::job(new GenerateDailyReport) — zadanie trafia wprost do kolejki; najczystszy wariant dla nowego kodu.

  • Schedule::command('reports:generate')->runInBackground() — komenda startuje jako osobny proces; dobra, gdy komenda już istnieje i działa długo.

  • - Wewnątrz komendy: GenerateDailyReport::dispatch() — gdy komenda robi kilka rzeczy, z których tylko część jest ciężka.

Warunek działania wszystkich trzech: sprawne workery pod Supervisorem (albo Horizon). Scheduler bez działających workerów to kolejka, która rośnie w nieskończoność — dlatego oba elementy konfigurujesz razem. Konfigurację workerów opisuję w poradniku Supervisor i systemd dla kolejek Laravel.

Częstotliwości i ograniczenia — ściągawka

Schedule::command('sync:orders')->everyFiveMinutes();
Schedule::command('reports:daily')->dailyAt('06:00');
Schedule::command('reports:weekly')->weeklyOn(1, '07:00');     // poniedziałek 7:00
Schedule::command('cleanup:temp')->monthlyOn(1, '03:00');
Schedule::job(new SyncPrices)->weekdays()->at('08:00')->timezone('Europe/Warsaw');

Metody, które ratują produkcję

Metoda Co robi Kiedy obowiązkowa
withoutOverlapping() Blokuje równoległe uruchomienie tego samego zadania Zawsze, gdy zadanie może trwać dłużej niż interwał
onOneServer() Tylko jeden serwer z klastra wykona zadanie Przy wielu serwerach aplikacji (wymaga wspólnego cache)
runInBackground() Cron nie czeka na zakończenie zadania Długie komendy
timezone('Europe/Warsaw') Strefa czasowa zadania Gdy serwer działa w UTC, a godziny mają znaczenie biznesowe
evenInMaintenanceMode() Zadanie działa też w trybie maintenance Synchronizacje, które nie mogą czekać
emailOutputTo() Wysyła output zadania mailem Rzadkie raporty i joby rozliczeniowe

Przykład z pełnym zabezpieczeniem

Schedule::job(new ImportProductsFromErp)
    ->everyThirtyMinutes()
    ->withoutOverlapping(10)        // blokada wygasa po 10 minutach
    ->onOneServer()
    ->timezone('Europe/Warsaw');

Uwaga: withoutOverlapping() bez argumentu trzyma blokadę do zakończenia zadania. Jeśli worker padnie w trakcie (np. OOM), blokada zostaje na zawsze i zadanie nigdy więcej się nie uruchomi. Podaj limit minut (withoutOverlapping(10)) jako bezpiecznik.

withoutOverlapping pod spodem — jak to działa

Blokada to wpis w cache (cache lock) o kluczu zadania. Pierwszy proces zakłada blokadę, kolejne ją widzą i pomijają uruchomienie. Po zakończeniu zadania blokada jest zwalniana. Konsekwencje:

  • Blokada wymaga współdzielonego cache — przy wielu serwerach file cache nie zadziała; potrzebny Redis/database.
  • Zablokowane uruchomienie nie jest kolejkowe — zadanie po prostu nie startuje w tej minucie.
  • Jeśli widzisz w logach „Skipping [zadanie] because it's already running" mimo że nic nie działa — blokada zawisła; usuń ją (cache:clear dla klucza albo dodaj limit minut).

Podgląd, testowanie i debug schedulera

php artisan schedule:list          # co, kiedy i jak często się uruchomi
php artisan schedule:run           # ręczne uruchomienie tego, co wypada „teraz"
php artisan schedule:work          # lokalny demon (zamiast crona) w development
php artisan schedule:test          # interaktywny wybór zadania do testu

Do monitoringu produkcji: każde zadanie schedulera warto logować (->onSuccess(), ->onFailure() z Laravela 10+)

Schedule::command('invoices:sync')
    ->everyFifteenMinutes()
    ->onSuccess(fn () => Log::info('invoices:sync OK'))
    ->onFailure(fn () => Log::error('invoices:sync FAILED'));

Alternatywnie emailOutputTo() dla zadań, których wynik chcesz widzieć na mailu (np. nocne raporty). A jeśli chcesz pełny obraz — Laravel Pulse pokazuje historię zadań schedulera w jednym panelu (porównanie Pulse i Telescope).

Scheduler a kolejki — typowe błędy

  • Ciężka praca w schedulerze — 5-minutowy import w Schedule::command() blokuje cron; inne zadania czekają. Wzorzec: scheduler → dispatch do kolejki.
  • Brak withoutOverlapping — przy zadaniu trwającym dłużej niż interwał uruchamiają się równoległe kopie; dwie synchronizacje naraz zdublują dane.
  • Brak onOneServer przy wielu serwerach — każde zadanie wykona się raz na każdym serwerze. Trzy serwery = trzy raporty i trzy maile.
  • Godziny bez strefy — serwer w UTC, zadanie dailyAt('06:00') odpala się o 8:00 czasu polskiego (albo o 4:00 przy zmianie czasu). Ustaw timezone('Europe/Warsaw').
  • Scheduler bez workerów — zadania Schedule::job() kolejkują się, ale nikt ich nie wykonuje. Sprawdź supervisorctl status i długość kolejki.

Najczęściej zadawane pytania

Czy Laravel Scheduler wymaga crona?

Tak — jeden wpis * * * * * php artisan schedule:run na serwerze (albo na jednym z serwerów klastra). Laravel Scheduler to warstwa decyzyjna nad cronem: cron co minutę pyta „co teraz uruchomić", a odpowiedź siedzi w kodzie aplikacji. W development zamiast crona działa php artisan schedule:work.

Jaka jest różnica między schedulerem a kolejką?

Scheduler odpowiada na pytanie kiedy (co godzinę, o 6:00, w poniedziałki), kolejka na pytanie jak wykonać pracę poza cyklem żądania (w tle, z retry). Wzorzec produkcyjny łączy oba: scheduler decyduje „teraz", kolejkuje zadanie, a worker je wykonuje z całą obsługą błędów.

Jak uniknąć nakładających się zadań cyklicznych?

Metodą withoutOverlapping() — zadanie zakłada blokadę w cache i kolejne uruchomienia są pomijane, dopóki poprzednie trwa. Podaj limit minut (withoutOverlapping(10)), żeby zawieszona blokada nie zablokowała zadania na zawsze. Blokada wymaga współdzielonego cache (Redis), jeśli aplikacja działa na wielu serwerach.

Jak przetestować zadanie schedulera lokalnie?

php artisan schedule:list pokaże definicje, php artisan schedule:test uruchomi wybrane zadanie ręcznie, a php artisan schedule:work uruchomi lokalny demon bez konfigurowania crona. Samą komendę możesz zawsze wywołać bezpośrednio: php artisan reports:daily.

Czy zadania schedulera działają podczas maintenance mode?

Domyślnie nie — Laravel wstrzymuje scheduler w trybie maintenance. Jeśli zadanie musi działać mimo przestoju (np. synchronizacja z ERP), dodaj ->evenInMaintenanceMode().


👉 Zadania cron nakładają się, raporty wysyłają się podwójnie, a cron blokuje się na godzinę? To klasyczne błędy konfiguracji schedulera. Opisz projekt na kontakt@informatix.com.pl lub przez formularz — uporządkujemy zadania cykliczne i kolejki.

📖 Zobacz również: Kolejki w Laravel i Laravel Horizon — poradnik, Supervisor i systemd dla kolejek Laravel, queue:work vs queue:listen oraz usługa Laravel development.

Darmowy PDF

Checklista wymagań do wyceny aplikacji

12 pytań kontrolnych, które warto przygotować przed rozmową z wykonawcą — szybsza wycena, mniej ukrytych kosztów.

Powiązane wpisy

09.10.2026

Laravel Horizon i kolejki w Laravel — kompletny poradnik [2026]

Kolejki w Laravel przenoszą ciężkie operacje poza cykl żądania HTTP, a Laravel Horizon daje monitoring i autoskalowanie workerów. Kompletny poradnik: wybór sterownika, konfiguracja produkcyjna, retry i idempotencja, testy, koszty wdrożenia.

Czytaj dalej

21.10.2026

Laravel Pulse i Telescope — monitoring aplikacji [2026]

Horizon odpowiada „co robią kolejki", Pulse „jak czuje się aplikacja", a Telescope „co się stało w tym żądaniu". Kompletny przewodnik: karty Pulse, bezpieczeństwo Telescope na produkcji i minimalny zestaw monitoringowy.

Czytaj dalej