Zum Inhalt springen

Die Verfügbarkeitsprüfungen von MainWP bleiben bei „Letzte Prüfung“ stehen

Von Philipp Kant 6 Min. Lesezeit

Die MainWP-Verfügbarkeitsüberwachung ist eine auf WordPress basierende Verfügbarkeitsprüfung, bei der der Status der Überwachungsinstanzen und die Heartbeat-Einträge in der Datenbank des MainWP-Dashboards gespeichert werden. Im Normalfall wählt WP-Cron die fälligen Überwachungsinstanzen aus, MainWP überprüft die Ziel-URLs, schreibt einen Heartbeat und aktualisiert den Zeitpunkt „Last Check“ der jeweiligen Überwachungsinstanz.

Ein Fehlerfall, den man kennen sollte: Der Scheduler kann ausgeführt werden, der Monitor kann ausgewählt werden, und dennoch wird die Überprüfung niemals abgeschlossen.

Genau das ist auf einem von Docker gehosteten MainWP-Dashboard hinter Traefik BasicAuth passiert. Die manuelle Force Check-Funktion funktionierte. Der automatische Monitor blieb jedoch beim alten Zeitstempel „Last Check“ hängen.

Die endgültige Korrektur bestand aus einer einzigen Zeile:

add_filter('mainwp_fetch_uptime_disable_check_multi_exec', '__return_true');

Wir haben dies in ein obligatorisches Plugin integriert, damit MainWP den einfachen sequenziellen cURL-Pfad anstelle des standardmäßigen Multi-cURL-Pfads verwendet.

WP-Cron lief, aber die Verfügbarkeitsprüfung wurde nicht abgeschlossen

Zunächst wurde angenommen, dass WP-Cron nicht funktionierte. So einfach war es jedoch nicht.

Die geplante Coolify-Aufgabe wurde alle fünf Minuten ausgeführt und ordnungsgemäß beendet. DISABLE_WP_CRON war auf true gesetzt, was in Ordnung ist, wenn ein externer Scheduler den WordPress-Cron auslöst. Die entsprechenden MainWP-Ereignisse waren vorhanden:

mainwp_cronuptimemonitoringcheck_action    jetzt    1 Minute
mainwp_cronupdatescheck_action jetzt    1 Minute
mainwp_cron_perform_general_process jetzt    1 Minute

Allerdings führte der Befehl „wp cron event run —due-now“ zunächst keine Ereignisse aus, obwohl fällige Ereignisse vorhanden waren. Das eigentliche Problem war ein fehlerhaftes WP-Cron-Array.

WordPress geht davon aus, dass das interne Cron-Array nach Zeitstempel sortiert ist. Liegt der erste Schlüssel in der Zukunft, kann der Scan der bereitstehenden Aufgaben beendet werden, bevor spätere überfällige Ereignisse erkannt werden.

Die Reparatur umfasste:

wp eval '$c=_get_cron_array(); ksort($c, SORT_NUMERIC); _set_cron_array($c);' --path=/var/www/html --allow-root

Danach wurde WP-Cron erneut verschoben. Die MainWP-Ereignisse wurden neu geplant. Doch Uptime sendete immer noch keinen neuen Heartbeat.

BasicAuth schien schuld zu sein, war aber nicht die Ursache

Das Dashboard war durch Traefik BasicAuth geschützt. Dies war einen Test wert, da WordPress bei eigenen Anfragen an die Dashboard-URL den Status 401 zurückgab:

wp_remote_post(admin_url("admin-ajax.php")) -> HTTP 401
wp_remote_get(site_url("wp-cron.php")) -> HTTP 401

Ein vorübergehend erforderliches Plugin fügte den HTTP-API-Anfragen von WordPress für die eigene Domain des Dashboards BasicAuth-Anmeldedaten hinzu. Dadurch funktionierten die normalen WordPress-Selbstanfragen wieder:

admin-ajax -> 400
wp-cron    -> 200

Doch die MainWP-Verfügbarkeit war damit noch nicht gewährleistet. Anschließend wurde BasicAuth am eigentlichen Traefik-Router deaktiviert und von außen überprüft:

curl https://mainwp.example.com/ -> HTTP 200

Die offiziellen MainWP-Cron-Dateien führten weiterhin zu demselben Stillstand:

php /var/www/html/wp-content/plugins/mainwp/cron/checkstatuschilds.php
php /var/www/html/wp-content/plugins/mainwp/cron/generalschedules.php

Ergebnis:

Herzschläge: 1
Zeitpunkt der letzten Überprüfung: 11:43:42
Start der automatischen Überwachung: aktuell
Zeitpunkt der automatischen Überwachung: 11:43:43

BasicAuth stellte ein echtes Problem bei der automatischen Verbindung für generische WordPress-HTTP-Anfragen dar. Es war nicht die Ursache für den Ausfall der integrierten Verfügbarkeitsüberwachung.

Die Datenbank zeigte an, dass MainWP den Durchlauf gestartet hat

Die Schlüsseltabelle war wp_mainwp_monitors.

Die Monitorzeile änderte ständig ein Feld:

dts_auto_monitoring_start: aktueller Zeitstempel

Die Vervollständigungsfelder blieben jedoch unverändert:

lasttime_check: 09.06.2026 11:43:42
dts_auto_monitoring_time: 09.06.2026 11:43:43
heartbeats_total: 1

Das bedeutet, dass der Scheduler den Monitor gefunden und als gestartet markiert hat. Der Antwort-Handler, der die Werte dts_auto_monitoring_time, lasttime_check und eine Heartbeat-Zeile schreibt, wurde nicht aufgerufen.

Diese Unterscheidung ist entscheidend. Sie schließt die meisten allgemeinen Ratschläge zu WP-Cron aus. Der Job wurde ausgelöst. Der Monitor wurde ausgewählt. Die Überprüfung des Pfads schlug danach fehl.

Der fehlerhafte Pfad war der Multi-cURL-Runner von MainWP

Der entsprechende MainWP-Code-Pfad lautet:

mainwp_cron_uptime_monitoring_check_action()
  -> MainWP_Uptime_Monitoring_Schedule::cron_uptime_check()
  -> MainWP_Uptime_Monitoring_Connect::check_monitors()

cron_uptime_check() setzt dts_auto_monitoring_start. Anschließend wählt check_monitors() zwischen zwei Ausführern:

$disable_multi_exec = apply_filters(
    'mainwp_fetch_uptime_disable_check_multi_exec',
    false
);

if (! $disable_multi_exec && curl_multi_exec ist verfügbar) {
    $this->check_multi_monitors($monitors, $glo_settings);
} else {
    $this->check_uptime_monitors($monitors, $glo_settings);
}

Auf diesem System hat MainWP den Standardpfad check_multi_monitors() über curl_multi_exec verwendet. Dieser Pfad führte nicht zu dem Handler, der den Monitor aktualisiert und den Heartbeat schreibt.

Durch die Erzwingung des sequenziellen Pfades wurde das Problem sofort behoben.

Die Lösung ist ein kleines, unverzichtbares Plugin

Erstellen Sie diese Datei:

/var/www/html/wp-content/mu-plugins/dsm-mainwp-uptime-no-multi.php

Mit folgenden Inhalten:

<?php
/**
 * Erzwingt, dass die in MainWP integrierte Verfügbarkeitsüberwachung sequentielles cURL
 * anstelle von curl_multi_exec verwendet.
 */
add_filter('mainwp_fetch_uptime_disable_check_multi_exec', '__return_true');

In Docker:

WP=$(docker ps --format '{{.Names}}' | grep -i wordpress | head -1)

cat > /tmp/dsm-mainwp-uptime-no-multi.php <<'PHP'
<?php
/**
 * Erzwingt, dass die in MainWP integrierte Verfügbarkeitsüberwachung sequentielles cURL
 * anstelle von curl_multi_exec verwendet.
 */
add_filter('mainwp_fetch_uptime_disable_check_multi_exec', '__return_true');
PHP

docker exec "$WP" mkdir -p /var/www/html/wp-content/mu-plugins
docker cp /tmp/dsm-mainwp-uptime-no-multi.php "$WP":/var/www/html/wp-content/mu-plugins/dsm-mainwp-uptime-no-multi.php
docker exec "$WP" chown www-data:www-data /var/www/html/wp-content/mu-plugins/dsm-mainwp-uptime-no-multi.php
rm /tmp/dsm-mainwp-uptime-no-multi.php

Ein unverzichtbares Plugin wird automatisch geladen. Es ist keine Aktivierung in wp-admin erforderlich. Es bleibt auch bei einer Neuinstallation erhalten, wenn sich wp-content auf einem persistenten Volume befindet.

Die Überprüfung erfolgt in Echtzeit, nicht über ein Cron-Protokoll

Eine erfolgreich ausgeführte geplante Aufgabe reicht nicht aus. Überprüfen Sie die MainWP-Heartbeat-Tabelle und überwachen Sie die Zeitstempel.

Führen Sie den MainWP-Verfügbarkeits-Cron-Job direkt aus:

docker exec "$WP" php /var/www/html/wp-content/plugins/mainwp/cron/checkstatuschilds.php

Überprüfen Sie anschließend den Status des Monitors:

docker exec "$WP" php /tmp/wp-cli.phar eval 'global $wpdb;
echo "Heartbeats: ".$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}mainwp_monitor_heartbeat")."\n";
$r=$wpdb->get_row("SELECT lasttime_check,dts_auto_monitoring_start,dts_auto_monitoring_time FROM {$wpdb->prefix}mainwp_monitors WHERE monitor_id=1",ARRAY_A);
foreach($r as $k=>$v){ echo "$k: ".($v>1000000000?gmdate("H:i:s",$v):$v)."\n"; }
echo "jetzt: ".gmdate("H:i:s")."\n";' --path=/var/www/html --allow-root

Nach der Korrektur änderte sich die Ausgabe von einem festgefahrenen einzelnen Herzschlag zu aktuellen Zeitstempeln:

Herzschläge: 3
Zeitpunkt der letzten Überprüfung: 16:14:03
Start der automatischen Überwachung: 16:14:03
Zeitpunkt der automatischen Überwachung: 16:14:04

Das ist der eigentliche Beweis. Der Monitor hat den Vorgang abgeschlossen und einen neuen Heartbeat geschrieben.

Der Kompromiss besteht darin, Parallelität gegen Zuverlässigkeit einzutauschen

Durch diesen Fix wird der parallele Verfügbarkeits-Runner von MainWP deaktiviert. Die Überprüfungen erfolgen nun nacheinander.

Dieser Kompromiss ist für einen kleinen Pilotbetrieb akzeptabel. Auch für kleinere Flotten ist er oft akzeptabel, sofern die Zeitüberschreitung und das Intervall vernünftig eingestellt sind. Bei einer größeren Flotte sollten Sie die Zahlen überprüfen:

FlottengrößeZu beachten
1–10 StandorteSequenzielle Überprüfungen sind in der Regel ausreichend. Behalten Sie die Lösung bei und beobachten Sie die Entwicklung.
10–50 StandorteVerringern Sie die Zeitüberschreitung; vermeiden Sie Intervalle von einer Minute, wenn die Standorte langsam sind.
50–100+ StandorteMessen Sie die Gesamtlaufzeit, passen Sie die Zeitüberschreitung an und erwägen Sie gegebenenfalls die Aufteilung der Überwachung oder die Nutzung eines externen Verfügbarkeitsdienstes.

Es geht nicht darum, dass sequentielles cURL besser ist. Es geht darum, dass eine korrekte, wenn auch langsamere Überprüfung einer parallelen Überprüfung vorzuziehen ist, die niemals einen Heartbeat schreibt.

Die Checkliste für die Fehlersuche

Wenn die Verfügbarkeitsüberwachung von MainWP bei „Letzte Überprüfung“ hängen bleibt, überprüfen Sie das System in folgender Reihenfolge:

  1. Überprüfen Sie, ob eine manuelle Zwangsüberprüfung funktioniert.
  2. Überprüfen Sie, ob die geplante Aufgabe ausgeführt wird.
  3. Überprüfen Sie, ob das MainWP-Verfügbarkeitsereignis vorhanden ist.
  4. Überprüfen Sie, ob ein „doing_cron“-Transient hängen geblieben ist.
  5. Überprüfen Sie, ob das WP-Cron-Array sortiert ist.
  6. Überprüfen Sie wp_mainwp_monitors auf dts_auto_monitoring_start und dts_auto_monitoring_time.
  7. Wenn die Aktualisierungen starten, die Zeit jedoch nicht, testen Sie den „no-multi“-Filter.

Das Diagnosesignal ist einfach:

dts_auto_monitoring_start ändert sich
dts_auto_monitoring_time bleibt unverändert
die Heartbeat-Frequenz steigt nicht an

Das weist über den Scheduler hinaus auf den Abruf-/Antwortpfad hin.

Häufig gestellte Fragen

Handelt es sich hierbei um einen Fehler in MainWP?

Es handelt sich um einen Kompatibilitätsfehler im Multi-cURL-Pfad von MainWP in dieser Laufzeitumgebung. Ich würde nicht behaupten, dass dies jede MainWP-Installation betrifft. In dieser Docker-/Coolify-/PHP-/cURL-Umgebung wurde der Standard-Multi-cURL-Pfad nicht ausgeführt. Der sequenzielle Pfad hingegen schon.

Ist BasicAuth der Grund dafür, dass die MainWP-Verfügbarkeitsüberwachung fehlgeschlagen ist?

BasicAuth war in diesem Fall nicht der Grund. Es blockierte zwar allgemeine WordPress-Selbstanfragen, doch die integrierte Verfügbarkeitsprüfung schlug weiterhin fehl, als BasicAuth vorübergehend deaktiviert und als ausgeschaltet bestätigt wurde.

Führt die Deaktivierung von Multi-cURL dazu, dass die Verfügbarkeitsüberwachung von MainWP nicht mehr sicher ist?

Nein. Es ändert sich lediglich die Ausführungsstrategie, nicht die Überwachungslogik. MainWP überprüft weiterhin dieselben Überwachungselemente und schreibt dieselben Heartbeat-Daten. Die Überprüfungen werden nun nacheinander statt parallel ausgeführt.

Sollte dieser Filter bei jeder MainWP-Installation verwendet werden?

Nein. Verwenden Sie diese Option, wenn der integrierte Verfügbarkeitsmonitor Läufe startet, diese aber nicht abschließt. Wenn der standardmäßige Multi-cURL-Pfad in Ihrer Umgebung funktioniert, behalten Sie ihn bei.

Sollten große Fuhrparks eine integrierte Verfügbarkeitsüberwachung nutzen?

Die integrierte Verfügbarkeitsüberwachung kann funktionieren, doch bei großen Flotten sind zeitliche Tests erforderlich. Wenn die sequenziellen Überprüfungen zu lange dauern, nutzen Sie den erweiterten Verfügbarkeitsmonitor von MainWP in Verbindung mit einem externen Anbieter oder einem dedizierten Verfügbarkeitssystem.


Tritt ein solcher Fehler in einer geschäftskritischen WordPress-Umgebung auf, lässt er sich selten durch eine einzige Einstellung beheben. Sie müssen den Scheduler, den Datenbankstatus, den Netzwerkpfad und den Laufzeitpfad überprüfen. Genau das ist unsere Aufgabe.

Sie haben etwas vor?

Schreiben Sie uns kurz, worum es geht und wie Erfolg für Sie aussieht. Wir lesen jede Nachricht und antworten innerhalb weniger Tage.