- Podstawy i kontekst uruchamiania zadań cyklicznych
- WP‑Cron a systemowy cron: różnice i kiedy który wybrać
- Cykl życia zadania i powiązane haki
- Dokładność i odporność: o czym pamiętać
- Szkielet własnej wtyczki i rejestracja harmonogramu
- Minimalna struktura plików
- Nagłówek wtyczki i podstawowe hooki
- Rejestracja interwałów i ustawienie zdarzenia
- Callback zadania i ładowanie środowiska
- Sprzątanie przy dezaktywacji
- Harmonogramy w praktyce: interwały, blokady, odporność
- Własne interwały vs wbudowane
- Blokady anty‑równoległe
- Idempotencja i bezpieczne powtórki
- Przetwarzanie wsadowe i limity
- Planowanie jednorazowe vs cykliczne
- Monitorowanie, debugowanie i narzędzia
- Prosty logger i dzienniki zdarzeń
- WP‑CLI do ręcznego uruchamiania i inspekcji
- Symulowanie słabego ruchu i błędów
- Inspekcja kolejki i zaległości
- Produkcja: wydajność, bezpieczeństwo i wdrożenia
- Most: systemowy cron wywołujący WP‑Cron
- Limity czasu, pamięci i rozmiaru wsadu
- Bezpieczeństwo danych i uprawnień
- Wersjonowanie i migracje
- Multisite i środowiska z replikacją
- Wzorce gotowe do użycia i najczęstsze scenariusze
- Czyszczenie starych danych i metadanych
- Synchronizacja z API zewnętrznym
- Wysyłka powiadomień i e‑maili
- Generowanie raportów i cache’owanie
- Mierniki, alerty i zdrowie procesów
- Checklist wdrożeniowy
Automatyzacja cyklicznych zadań w wtyczkach to niezbędny element do wysyłki powiadomień, czyszczenia starych danych, synchronizacji z API czy generowania raportów. Poniższy przewodnik pokazuje, jak zaprojektować i wdrożyć cron w swojej wtyczka, krok po kroku: od wyboru mechanizmu (WP‑Cron vs systemowy), przez rejestrację harmonogramu i obsługę hooków, po testy, logowanie, bezpieczne blokady i praktyki produkcyjne poprawiające wydajność oraz stabilność. Znajdziesz tu konkretne receptury, typowe pułapki i sposoby ich omijania.
Podstawy i kontekst uruchamiania zadań cyklicznych
WP‑Cron a systemowy cron: różnice i kiedy który wybrać
WordPress dostarcza mechanizm WP‑Cron, który uruchamia zadania przy okazji wejścia użytkownika na stronę. Nie działa w tle stale – „budzi się” przy ruchu. To oznacza, że w godzinach bez odwiedzin harmonogram może się opóźnić, a przy dużym ruchu – odpalić wiele równoległych instancji. Z kolei systemowy cron (Linux/macOS/serwer) odpala zadania o dokładnych porach, niezależnie od ruchu WWW, jednak wymaga dostępu do środowiska serwera (panel, SSH) i osobnej konfiguracji.
Wybór strategii:
- WP‑Cron: szybki start, brak dostępu do serwera nie jest problemem, dobra opcja na małe lub średnie instalacje.
- Systemowy cron: wymagany dla twardych SLA czasowych, przetwarzania dużych kolejek, zadań wymagających przewidywalności i odporności na brak ruchu.
Cykl życia zadania i powiązane haki
Typowy przepływ w WP‑Cron wygląda tak:
- Podczas aktywacji wtyczki rejestrujesz zdarzenie czasowe i interwał (np. co 5 minut).
- Hook „cronowy” wskazuje na funkcję/callback, która wykona faktyczną robotę.
- WordPress przy wejściu użytkownika sprawdza kolejkę zdarzeń i uruchamia zaległe.
- Przy dezaktywacji wtyczki sprzątasz po sobie, anulując zaplanowane zdarzenia.
Dokładność i odporność: o czym pamiętać
WP‑Cron nie gwarantuje sekundowej dokładności; wydarzenia będą uruchamiane „tak szybko, jak to możliwe”, o ile jest ruch. Z tego powodu logika zadania powinna być:
- Odporna na wielokrotne uruchomienie (tzw. idempotencja).
- Chroniona przed równoległym wykonaniem (np. poprzez lekką blokada w bazie lub transient).
- Projektowana w partiach (batching), aby unikać timeoutów i przekroczeń pamięci.
Szkielet własnej wtyczki i rejestracja harmonogramu
Minimalna struktura plików
Proponowany układ:
- /wp-content/plugins/my-cron-plugin/my-cron-plugin.php – plik główny z nagłówkiem wtyczki, rejestracją hooków, aktywacją/dezaktywacją.
- /wp-content/plugins/my-cron-plugin/includes/Tasks.php – logika zadań.
- /wp-content/plugins/my-cron-plugin/includes/Schedule.php – funkcje harmonogramu (rejestracja interwałów, ustawianie zdarzeń).
- /wp-content/plugins/my-cron-plugin/includes/Lock.php – narzędzia do blokad i idempotencji.
- /wp-content/plugins/my-cron-plugin/includes/Logger.php – prosty logger do debugowania.
Nagłówek wtyczki i podstawowe hooki
W pliku my-cron-plugin.php umieść nagłówek oraz rejestrację aktywacji/dezaktywacji:
- register_activation_hook(__FILE__, 'my_cron_plugin_activate’); – podczas aktywacji ustaw harmonogram.
- register_deactivation_hook(__FILE__, 'my_cron_plugin_deactivate’); – podczas dezaktywacji wyczyść zaplanowane zdarzenia.
Dalej, dołącz pliki includes oraz zarejestruj akcję cronową:
- add_action(’my_cron_plugin_task’, 'my_cron_plugin_run_task’); – callback do faktycznego zadania.
Rejestracja interwałów i ustawienie zdarzenia
Aby dodać niestandardowy interwał (np. 5 minut), użyj filtra cron_schedules:
- add_filter(’cron_schedules’, function ($schedules) { $schedules[’every_five_minutes’] = [’interval’ => 300, 'display’ => 'Co 5 minut’]; return $schedules; });
Następnie, w funkcji aktywacyjnej:
- if (!wp_next_scheduled(’my_cron_plugin_task’)) { wp_schedule_event(time() + 60, 'every_five_minutes’, 'my_cron_plugin_task’); }
Powyższe ustawi pierwsze uruchomienie za minutę, a kolejne zgodnie z interwałem.
Callback zadania i ładowanie środowiska
Callback (np. my_cron_plugin_run_task) powinien:
- Sprawdzić blokadę (czy nie trwa inna instancja).
- Załadować zależności (np. klasy z includes/).
- Uruchomić pracę w małych porcjach, logując postęp.
- Uwolnić blokadę po zakończeniu, niezależnie od wyniku.
W tym miejscu warto zaimplementować retry i obróbkę wyjątków.
Sprzątanie przy dezaktywacji
W my_cron_plugin_deactivate wyrejestruj zdarzenia:
- $timestamp = wp_next_scheduled(’my_cron_plugin_task’);
- if ($timestamp) { wp_unschedule_event($timestamp, 'my_cron_plugin_task’); }
- delete_transient(’my_cron_plugin_lock’); – jeśli stosujesz transienty do blokad.
Dzięki temu nie pozostawisz „sierocych” wpisów w harmonogramie.
Harmonogramy w praktyce: interwały, blokady, odporność
Własne interwały vs wbudowane
WordPress posiada wbudowane interwały (hourly, twicedaily, daily). Niestandardowe dodamy filtrem cron_schedules. Przy krótkich interwałach (np. co minutę) pamiętaj o kosztach – jeśli nie masz ruchu, WP‑Cron może się spóźniać; jeśli ruch jest duży, zadania mogą się kumulować. W takich przypadkach rozważ systemowy cron lub alternatywne mechanizmy kolejkowania (Action Scheduler).
Blokady anty‑równoległe
Aby uniknąć równoległego uruchomienia:
- Ustaw transient: set_transient(’my_cron_plugin_lock’, 1, 15 * MINUTE_IN_SECONDS); jeśli już istnieje – wyjdź.
- W kodzie zadania na start sprawdź get_transient(’my_cron_plugin_lock’); jeśli jest – zakończ bez pracy.
- Po zakończeniu pracy delete_transient(’my_cron_plugin_lock’).
Jeżeli używasz obiektu cache zewnętrznego, weryfikuj zachowanie transientów; w MVP‑wariancie można użyć opcji w bazie z operacją add_option jako prymitywnego locka (z obsługą TTL).
Idempotencja i bezpieczne powtórki
Projektuj zadania tak, aby wielokrotne odpalenie nie szkodziło:
- Przetwarzaj rekordy po kluczu rosnącym (np. ID) i zapisuj ostatni przetworzony punkt kontrolny (checkpoint) w opcji.
- Używaj znaczników stanu (np. data_synchronized_at) zamiast „flagi przetworzone” bez czasu – pozwala to na bezpieczne rekalkulacje.
- Sprawdzaj wersję danych i warunki wyścigu (select‑then‑update z walidacją).
To kluczowe, gdy WP‑Cron odpali się dwa razy z rzędu, bądź gdy nastąpi awaria w połowie zadania.
Przetwarzanie wsadowe i limity
Unikaj „one‑shot” nadmiernie ciężkich zadań. Lepszy jest batch np. 100 rekordów na cykl:
- Pobierz 100 elementów spełniających kryteria.
- Przetwórz je z krótkimi timeoutami I/O.
- Zaktualizuj checkpoint i zapisz metryki (ile, czas trwania, błędy).
Jeśli kolejka jest długa, dopuszczalne jest odpalenie cron co 1–5 minut i systematyczne przegryzanie zadań.
Planowanie jednorazowe vs cykliczne
Masz dwie podstawowe metody:
- Jednorazowe: wp_schedule_single_event(timestamp, 'my_cron_plugin_task_once’, [$payload]); dobre do retry/backoff lub akcji „za X minut”.
- Cykliczne: wp_schedule_event(start, 'every_five_minutes’, 'my_cron_plugin_task’); do regularnych prac utrzymaniowych.
Pamiętaj, że anulowanie pojedynczego wydarzenia wymaga podania tego samego payloadu, który był zaplanowany.
Monitorowanie, debugowanie i narzędzia
Prosty logger i dzienniki zdarzeń
Dobry logger w wtyczce ułatwia życie:
- Funkcja my_cron_plugin_log($level, $message, $context = []): zapis do wp-content/uploads/my-cron-plugin/log-YYYY-MM-DD.txt.
- Loguj start/stop, liczbę elementów, czas trwania, identyfikator blokady, błędy (stack trace).
- W testach lokalnych włącz WP_DEBUG_LOG i monitoruj debug.log.
Zadbaj, by logi rotowały (np. dziennie) i nie gromadziły wrażliwych danych PII bez potrzeby.
WP‑CLI do ręcznego uruchamiania i inspekcji
Narzędzie WP-CLI pozwala uruchamiać i debugować:
- wp cron event list – lista zaplanowanych zdarzeń.
- wp cron event run my_cron_plugin_task – wymusza uruchomienie akcji.
- wp cron schedule list – lista interwałów.
- wp option get my_cron_plugin_checkpoint – sprawdzenie postępu.
Możesz też dodać własną komendę: wp my-cron-plugin run-batch, która wywoła bezpośrednio logikę i pominie harmonogram.
Symulowanie słabego ruchu i błędów
Aby przetestować opóźnienia WP‑Cron:
- Wyłącz wywołanie WP‑Cron przy każdym żądaniu (DISABLE_WP_CRON) i uruchamiaj go co minutę systemowym cronem – zobaczysz, jak radzi sobie Twój kod.
- Wstrzykuj sztuczne błędy API i timeouty, sprawdzając, czy retry/backoff działają zgodnie z planem.
- Sprawdź zachowanie blokady w sytuacji awaryjnego wyjścia (czy TTL zwolni lock, a kolejne uruchomienia ruszą).
Inspekcja kolejki i zaległości
Jeśli podejrzewasz zaległości:
- Porównaj liczbę zaplanowanych zdarzeń z liczbą zadań w kolejce do przetworzenia.
- W logach szukaj długich czasów trwania; rozbijaj batch na mniejsze porcje.
- Sprawdź ograniczenia hostingu (CPU, I/O, jednoczesne procesy PHP, max_execution_time).
W razie potrzeby zwiększ interwał lub przenieś cięższe prace na systemowy cron lub dedykowaną kolejkę.
Produkcja: wydajność, bezpieczeństwo i wdrożenia
Most: systemowy cron wywołujący WP‑Cron
Najczęstszy wzorzec produkcyjny:
- W wp-config.php ustaw define(’DISABLE_WP_CRON’, true); aby WP nie odpalał cron przy każdym wejściu.
- W systemowym cronie (crontab) dodaj: */1 * * * * php /ścieżka/do/wp/wp-cron.php > /dev/null 2>&1 – lub curl https://twoja-domena.pl/wp-cron.php?doing_wp_cron=1.
Zyskujesz przewidywalność bez konieczności przepisywania logiki.
Limity czasu, pamięci i rozmiaru wsadu
Dostosuj wielkość batcha do limitów hostingu. W callbacku:
- Użyj krótkich timeoutów HTTP (wp_remote_get/post z timeout 5–10 s).
- Ustaw konserwatywne limity batcha (np. 50–200 rekordów) i mierz realny czas trwania.
- W razie potrzeby dziel większe kroki na etapy z checkpointami.
Pamiętaj o memory_get_usage i prostych metrykach, które podpowiedzą, gdzie cięcia są potrzebne.
Bezpieczeństwo danych i uprawnień
Callback cronowy działa w kontekście WordPressa, więc:
- Waliduj dane wejściowe (nawet jeśli pochodzą z wewnętrznych źródeł).
- Szanuj prywatność – nie zapisuj danych wrażliwych do logów, maskuj tokeny.
- Rotuj klucze API; przechowuj w wp_options z autoload = no lub w bezpiecznym magazynie.
Jeśli zadanie wykonuje operacje na plikach, sprawdź uprawnienia katalogów i obsługuj błędy dyskowe.
Wersjonowanie i migracje
Podczas aktualizacji wtyczki:
- Używaj opcji my_cron_plugin_version i funkcji upgrade_routine: jeśli wersja się zmieniła, zaktualizuj interwały i hooki.
- Zapewnij „migracje” danych (np. zmiana formatu checkpointu) jako osobne, idempotentne kroki.
- W stagingu przetestuj harmonogram: czy zdarzenia nie dublują się po update?
Zachowaj kompatybilność wsteczną, jeśli Twoi użytkownicy mają różne wersje WordPressa.
Multisite i środowiska z replikacją
W multisite każdy blog ma własny harmonogram. Decyduj:
- Czy instalować i planować zadania per‑site (switch_to_blog w pętli)?
- Czy centralne zadanie ma iterować po wszystkich blogach? Zwróć uwagę na czas wykonania i limity.
Przy replikacji bazy (master‑slave) pamiętaj, że WP‑Cron powinien wykonywać się na instancji mającej prawo zapisu. Zadbaj, by blokady trafiały na mastera i nie rozminęły się w odczytach z replica.
Wzorce gotowe do użycia i najczęstsze scenariusze
Czyszczenie starych danych i metadanych
Powszechny przypadek to porządkowanie bazy:
- Co noc: pobierz 500 najstarszych wpisów‑do‑usunięcia, usuń bezpiecznie, zarejestruj liczbę rekordów i czas.
- Idempotencja: przechowuj ostatnie ID i datę, powtarzaj do skutku, dopóki kolejka nie będzie pusta.
- Bezpieczeństwo: używaj wp_delete_post z force_delete i sprawdzaj uprawnienia (map_meta_cap).
Synchronizacja z API zewnętrznym
Co 5–15 minut odświeżaj katalog produktów lub stany magazynowe:
- Paginate po 100–200 rekordów, zapisuj etag/last_modified, aby unikać pełnych pobrań.
- Obsłuż kody błędów 429/5xx: backoff (wp_schedule_single_event z +5, +15, +30 min).
- Loguj numer strony, liczbę zmian i ewentualne konflikty wersji.
Wysyłka powiadomień i e‑maili
Wysyłaj porcjami, aby nie wpaść na limity SMTP:
- Batch 50–100 wiadomości na cykl, z kolejką (tabela lub custom post type „mail_job”).
- Retry per‑wiadomość z ograniczoną liczbą prób, zapisem przyczyny porażki.
- Ogranicz równoległość przez lock i sprawdzanie dostępnej puli.
Generowanie raportów i cache’owanie
Raz dziennie generuj raporty PDF/CSV i odświeżaj cache:
- Korzystaj z tymczasowych plików i atomowego przenoszenia (rename) po zakończeniu generacji.
- Cache’uj wyniki drogich zapytań i unieważniaj je po przetworzeniu partii danych.
- Dostarczaj status (np. opcja last_report_generated_at) oraz link do ostatniego pliku.
Mierniki, alerty i zdrowie procesów
Dodaj prosty „health check”:
- Opcja last_success_at i last_failure_at dla każdego zadania.
- Jeżeli last_success_at starsze niż 1h, wyślij alert do administratora.
- Raport tygodniowy: sumaryczna liczba przetworzonych elementów, średni czas wsadu, odsetek błędów.
Takie metryki pomagają wykryć ciche awarie, zanim staną się widoczne dla użytkowników.
Checklist wdrożeniowy
Przed uruchomieniem na produkcji:
- Testy lokalne: ręczne uruchomienie zadania, wymuszenie warunków brzegowych.
- Staging: weryfikacja harmonogramu, blokady, logów i wskaźników.
- Produkcja: DISABLE_WP_CRON + systemowy cron co 1–5 minut lub zachowanie domyślne – decyzja świadoma, uzasadniona ruchem.
- Monitoring: alerty na brak sukcesu i wzrost błędów.
- Dokumentacja: opis interwałów, hooków, ścieżek logów i procedur awaryjnych.
Na koniec warto pamiętać, że niezależnie od tego, czy używasz WP‑Cron czy systemowego crona, najważniejsze są: przejrzysta architektura, ograniczanie skutków błędów, świadome zarządzanie interwałami i obciążeniem oraz dbałość o bezpieczeństwo i przewidywalność. Dzięki tym zasadom nawet rozbudowane harmonogramy pozostaną stabilne i łatwe w utrzymaniu, a Twoje zadania będą wykonywać się terminowo i bez zbędnych niespodzianek.