CLI-Skripte

Command-Line-Skripte und Wartung

Skripte

php modules_v4/cronjob/cli/tick.php              # alle fälligen Jobs ausführen
php modules_v4/cronjob/cli/tick.php --dry-run    # anzeigen, was ausgeführt würde
php modules_v4/cronjob/cli/tick.php --job=<name> # einen bestimmten Job jetzt ausführen
php modules_v4/cronjob/cli/tick.php --strict     # Exit 1 wenn ein Job fehlgeschlagen ist
php modules_v4/cronjob/cli/tick.php --full-output # vollständige Job-Ausgabe echo (Debugging!)
php modules_v4/cronjob/cli/watch.php             # Watch-Daemon starten

Exit-Codes: 0 = Tick lief (Job-Fehler werden in der DB protokolliert), 1 = Umgebungsproblem oder (mit --strict) mindestens ein Job fehlgeschlagen.

Log-Hygiene: stdout trägt nur Summary-Zeilen. Die vollständige Job-Ausgabe liegt in der Ausführungshistorie (nur Admin). --full-output niemals in einen weltlesbaren Ort umleiten.

Für die Fehlersuche unterstützt das tick.php Skript auch die Parameter -v und -vv, damit die Konsolen-Ausgabe ausführlicher ausfällt.

Acceptance-Test

php modules_v4/cronjob/cli/smoke-job.php            # zeigt ok, Exit 0
php modules_v4/cronjob/cli/smoke-job.php --sleep=10 # lebt 10 s (Timeout-Test)

Erstellen Sie einen Job mit Befehl modules_v4/cronjob/cli/smoke-job.php, klicken Sie Jetzt ausführen, warten Sie eine Minute — die Verlauf-Seite sollte eine grüne ok-Zeile zeigen.

Konventionen für Job-Skripte

Neue Job-Skripte in anderen Modulen müssen diese Konventionen einhalten:

  • Ort modules_v4/<module>/cli/, aufgerufen als php modules_v4/<module>/cli/<script>.php
  • Beginnen mit require autoload.php und CliBootstrap::guard()
  • Idempotent und inkrementell (--limit, --since), batched
  • Exit-Code 0 bei Erfolg
  • Keine interaktive Eingabe; alles über CLI-Optionen
  • Template-Dateien sind mit _ Präfix versehen (von der Job-Entdeckung ausgeschlossen)
  • Eigene CLI-Skripte können leicht auf folgende Weise begonnen werden:
    • einer Vorlage: _template-maintenance.php – diese in das Verzeichnis cli/ des eigenen Moduls kopieren, umbenennen und entsprechend anpassen
    • oder, falls das Modul bereits von Cronjobs abhängt, kann dieser Bootstrap-Vorgang stattdessen an den gemeinsamen CLI-Wrapper delegiert werden

Wartungsskripte schreiben

Die Vorlage verwenden

_template-maintenance.php ist eine Vorlage zum Kopieren und Einfügen für länger laufende Wartungsaufträge.
Die Konventionen:

  • SAPI-Guard: Jedes Skript beginnt mit CliBootstrap::guard() – das Verzeichnis ist über eine URL erreichbar, der Guard gibt den Status 403 zurück, anstatt das Skript auszuführen.
  • Bootstrap: Verwende CliBootstrap::boot() – die zentrale CLI-Bootstrap-Sequenz (App-Bootstrap, i18n, Konfiguration, Datenbank) mit einem harten Fehler bei fehlender Konfiguration oder fehlender Datenbankverbindung.
  • Argumente: einfaches $argv (--limit=N, --help).
  • Sperre: flock() auf data/<module>/<name>.lock, damit sich überlappende Cron-Läufe nicht kollidieren; eine gehaltene Sperre ist kein Fehler (Beendigungscode 0).
  • Idempotente Batches: Gestalten Sie den Job so, dass ein Lauf in etwa 5–10 Minuten abgeschlossen ist und der nächste Lauf dort fortgesetzt wird, wo der letzte aufgehört hat.
  • Protokollierung: einfache Zeilen in der Standardausgabe (Cron-E-Mail / Protokolldatei). Geben Sie niemals personenbezogene Daten aus – Zähler und XREFs, niemals Namen.
  • Exit-Codes: 0 = ok (einschließlich „nichts zu tun“, „Sperre gehalten“), 1 = Fehler.

CLI-Wrapper verwenden

Ein Job-Skript, das webtrees + Datenbank braucht, kann den Bootstrap an den gemeinsamen Wrapper des Cronjob-Moduls delegieren:

  1. Payload modules_v4/<module>/cli/<name>.logic.php — die eigentliche Logik.
  2. Stub modules_v4/<module>/cli/<name>.php — worauf die Job-Zeile zeigt:
<?php
declare(strict_types=1);
$wrapper = __DIR__ . '/../../cronjob/cli/wrap.php';
if (is_file($wrapper)) {
    require $wrapper;
} else {
    fwrite(STDERR, "cronjob module required for this job\n");
    exit(1);
}

wrap.php bootstrapt webtrees + DB und inkludiert dann das Payload (Geschwisterdatei mit .logic.php-Erweiterung). Der Payload-Pfad wird aus dem Entry-Skript abgeleitet, nie aus einem Argument genommen.

Zuletzt geändert 04.11.2026: cross-references (60f426f)