WordPress i błąd „A scheduled event has failed”?

Wordpress blad wp cron
Andre Selfie

Linux devotee and Bournemouth-based IT expert, obsessed with homelabbing, server performance, and elegant Python code.

Każdy administrator strony na WordPressie zna to uczucie. Logujesz się do panelu, a tam czeka na Ciebie komunikat: „A scheduled event has failed”. Serce na chwilę staje. Czy strona padła? Czy to poważna awaria?

Spokojnie! Zanim zaczniesz panikować, weź głęboki oddech. Ten błąd, choć brzmi poważnie, rzadko oznacza katastrofę. Najczęściej jest to po prostu sygnał, że wewnętrzny mechanizm harmonogramu zadań w WordPressie nie działa optymalnie.

W tym artykule wyjaśnimy, czym jest ten błąd, dlaczego się pojawia i jak go profesjonalnie naprawić w różnych konfiguracjach serwerowych.

Czym jest WP-Cron?

WordPress musi wykonywać cykliczne zadania w tle: publikować zaplanowane posty, tworzyć kopie zapasowe czy skanować witrynę w poszukiwaniu wirusów (jak w przypadku błędu wf_scan_monitor od wtyczki Wordfence). Do obsługi tych operacji używa wbudowanego mechanizmu o nazwie WP-Cron.

Problem polega na tym, że WP-Cron nie jest prawdziwym demonem cron znanym z systemów uniksowych. To „pseudo-cron”, który ma fundamentalną wadę: uruchamia się tylko wtedy, gdy ktoś odwiedzi Twoją stronę internetową.

  • Na stronach o małym ruchu: Jeśli nikt nie wchodzi na witrynę, zadania nie są wykonywane o czasie, co prowadzi do błędów.
  • Na stronach o dużym ruchu: WP-Cron jest wywoływany przy każdym załadowaniu strony, co generuje niepotrzebne obciążenie serwera.

W obu przypadkach rozwiązanie jest takie samo: wyłączyć wbudowany WP-Cron i zastąpić go stabilnym, systemowym zadaniem cron.

Scenariusz 1: Pojedyncza strona WordPress

To podstawowa i najczęstsza konfiguracja. Rozwiązanie problemu jest proste i sprowadza się do dwóch kroków.

Krok 1: Wyłącz wbudowany mechanizm WP-Cron

Edytuj plik wp-config.php w głównym katalogu swojej strony i dodaj poniższą linię:

define('DISABLE_WP_CRON', true);

Krok 2: Skonfiguruj systemowy cron

Zaloguj się do swojego serwera przez SSH i wpisz crontab -e, aby edytować listę zadań systemowych. Następnie dodaj jedną z poniższych linii, która co 5 minut będzie wywoływać mechanizm crona WordPressa we właściwy sposób.

  • Metoda z wget:*/5 * * * * wget -q -O - https://twojadomena.pl/wp-cron.php?doing_wp_cron >/dev/null 2>&1
  • Metoda z curl:*/5 * * * * curl -s https://twojadomena.pl/wp-cron.php?doing_wp_cron >/dev/null 2>&1

Pamiętaj, aby podmienić twojadomena.pl na właściwy adres. Od teraz zadania będą wykonywane regularnie, niezależnie od ruchu na stronie.

Scenariusz 2: Wiele stron na standardowym serwerze

Jeśli zarządzasz wieloma stronami, dodawanie osobnej linii w crontab dla każdej z nich jest niepraktyczne i trudne w utrzymaniu. Lepszym rozwiązaniem jest stworzenie jednego skryptu, który automatycznie znajdzie wszystkie instalacje WordPressa i uruchomi dla nich zadania.

Krok 1: Stwórz plik skryptu

Utwórz plik, np. /usr/local/bin/run_all_wp_crons.sh, i wklej do niego poniższą zawartość. Skrypt przeszukuje katalog /var/www/ w poszukiwaniu plików wp-config.php.

#!/bin/bash

# =================================================================
# Skrypt do uruchamiania zadań cron dla wszystkich stron WordPress
# Zoptymalizowany dla struktury katalogów ISPConfig
# =================================================================

# Główny katalog, w którym znajdują się FAKTYCZNE pliki stron w ISPConfig
SITES_ROOT="/var/www/clients/"

# Ścieżka do interpretera PHP (może wymagać dostosowania)
PHP_EXECUTABLE="/usr/bin/php"

# Logowanie (opcjonalne, ale przydatne do debugowania)
LOG_FILE="/var/log/wp_cron_runner.log"
echo "Rozpoczynam uruchamianie zadań cron (ISPConfig): $(date)" >> $LOG_FILE

# Znajdź wszystkie pliki wp-config.php i uruchom dla nich wp-cron.php
find "$SITES_ROOT" -name "wp-config.php" -print0 | while IFS= read -r -d '' config_file; do

    # Wyodrębnij katalog, w którym znajduje się WordPress
    WP_DIR=$(dirname "$config_file")

    # Wyodrębnij nazwę użytkownika (np. web4) z ścieżki
    # Jest to siódmy element w ścieżce /var/www/clients/client4/web4/web/
    WP_USER=$(echo "$WP_DIR" | awk -F'/' '{print $6}')

    if [ -z "$WP_USER" ]; then
        echo "-> OSTRZEŻENIE: Nie udało się określić użytkownika dla: $WP_DIR" >> $LOG_FILE
        continue
    fi

    # Sprawdź, czy plik wp-cron.php istnieje w tym katalogu
    if [ -f "$WP_DIR/wp-cron.php" ]; then
        echo "-> Uruchamiam cron dla: $WP_DIR jako użytkownik: $WP_USER" >> $LOG_FILE
        # Uruchom wp-cron.php używając PHP CLI, przełączając się na właściwego użytkownika
        su -s /bin/sh "$WP_USER" -c "(cd '$WP_DIR' && '$PHP_EXECUTABLE' wp-cron.php)"
    else
        echo "-> OSTRZEŻENIE: Znaleziono wp-config, ale brak wp-cron.php w: $WP_DIR" >> $LOG_FILE
    fi

done

echo "Zakończono: $(date)" >> $LOG_FILE
echo "---" >> $LOG_FILE

Krok 2: Nadaj skryptowi uprawnienia do wykonania

chmod +x /usr/local/bin/run_all_wp_crons.sh

Krok 3: Stwórz jedno zadanie cron do zarządzania wszystkim

Teraz Twój crontab -e może zawierać tylko jedną linię:

*/5 * * * * /usr/local/bin/run_all_wp_crons.sh >/dev/null 2>&1

Scenariusz 3: Wiele stron z panelem ISPConfig

Panel ISPConfig używa specyficznej struktury katalogów z dowiązaniami symbolicznymi (symlinkami), np. /var/www/twojadomena.pl wskazuje na /var/www/clients/client1/web1/. Użycie powyższego skryptu mogłoby spowodować podwójne wykonanie zadań.

Aby tego uniknąć, należy zmodyfikować skrypt tak, by przeszukiwał tylko docelowy katalog clients.

Krok 1: Stwórz skrypt zoptymalizowany dla ISPConfig

Utwórz plik /usr/local/bin/run_ispconfig_crons.sh. Zwróć uwagę na zmianę w zmiennej SITES_ROOT.

#!/bin/bash

# Skrypt do uruchamiania zadań cron dla wszystkich stron WordPress
# Zoptymalizowany dla struktury katalogów ISPConfig

# Przeszukujemy tylko katalog z faktycznymi plikami stron
SITES_ROOT="/var/www/clients/"

# Ścieżka do interpretera PHP
PHP_EXECUTABLE="/usr/bin/php"

# Opcjonalny plik logu do śledzenia postępów
LOG_FILE="/var/log/wp_cron_runner.log"
echo "Rozpoczynam uruchamianie zadań cron (ISPConfig): $(date)" >> $LOG_FILE

find "$SITES_ROOT" -name "wp-config.php" -print0 | while IFS= read -r -d '' config_file; do
    
    WP_DIR=$(dirname "$config_file")

    if [ -f "$WP_DIR/wp-cron.php" ]; then
        echo "-> Uruchamiam cron dla: $WP_DIR" >> $LOG_FILE
        (cd "$WP_DIR" && "$PHP_EXECUTABLE" wp-cron.php)
    fi

done

echo "Zakończono: $(date)" >> $LOG_FILE
echo "---" >> $LOG_FILE

Krok 2 i 3 są analogiczne jak w scenariuszu 2: nadaj skryptowi uprawnienia (chmod +x) i dodaj jedną linię do crontab -e, wskazując na nowy plik skryptu.

Podsumowanie

Błąd „A scheduled event has failed” to nie powód do paniki, a raczej zaproszenie do ulepszenia swojej infrastruktury. To szansa, by przejść z zawodnego, wbudowanego mechanizmu WordPressa na solidne, profesjonalne rozwiązanie systemowe, które gwarantuje stabilność i wydajność.

Niezależnie od konfiguracji serwera, teraz masz narzędzia, by spać spokojnie, wiedząc, że Twoje zaplanowane zadania wykonują się jak w szwajcarskim zegarku.

Andre Selfie
Andrzej Majewski

Moja fascynacja technologią zaczęła się podczas studiów informatycznych na Uniwersytecie Zielonogórskim. Od czasu przeprowadzki do Wielkiej Brytanii w 2015 roku i osiedlenia się na stałe w Bournemouth, przekułem tę pasję w karierę zawodową poświęconą infrastrukturze o wysokiej wydajności.W głębi duszy jestem entuzjastą Linuxa – to zaangażowanie wykracza poza moją pracę zawodową w SolutionsInc i obejmuje również mój rozbudowany, prywatny homelab. Niezależnie od tego, czy zarządzam złożonymi architekturami serwerowymi przez ISPConfig, buduję systemy VoIP w ramach Phones Rescue, czy tworzę narzędzia do automatyzacji w Pythonie, najlepiej czuję się, podejmując wyzwania związane z projektowaniem wydajnych rozwiązań open-source

Komentarze

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Wymagane pola są oznaczone *