cronjobs

Quelle: https://redaxo.org/doku/main/cronjobs

Cronjobs

Einführung

Zweck des Cronjob-AddOns

Das Cronjob-AddOn ermöglicht die automatisierte, zeitgesteuerte Ausführung von Aufgaben in REDAXO. Es ist Teil der REDAXO-Basisinstallation, muss jedoch bei Bedarf separat installiert werden. Mit diesem AddOn können beliebig viele Cronjobs definiert werden, die gemäß individuellen Zeitplänen ausgeführt werden.

Anwendungsfälle

Typische Einsatzgebiete für Cronjobs:

  • Wartungsaufgaben: Regelmäßige Datenbank-Optimierung und Bereinigung

  • Content-Management: Zeitgesteuertes Veröffentlichen oder Archivieren von Artikeln

  • Backup-Routinen: Automatische Datenbank- und Datei-Backups

  • Synchronisation: Abgleich mit externen Systemen (RSS-Feeds, APIs)

  • Benachrichtigungen: Versand von E-Mail-Reports oder Newsletter

  • Datenverarbeitung: Import/Export von Daten, Bildoptimierung

  • Monitoring: Überwachung von System-Metriken und Alarmierung

Installation und Konfiguration

  • Installation: Das Cronjob-AddOn über den Installer aktivieren

  • Konfiguration: Unter AddOns > Cronjob die Verwaltungsoberfläche aufrufen

  • Server-Cronjob: Für optimale Performance einen Server-Cronjob einrichten (siehe Server-Cronjob einrichten)

Cronjob erstellen

Grundeinstellungen

Name

Ein aussagekräftiger Name für den Cronjob, z.B. Tägliches Backup, RSS-Feed Import oder Cache-Bereinigung.

Beschreibung

Eine detaillierte Beschreibung der Aufgabe. Diese hilft bei der späteren Wartung und Dokumentation.

Status

  • Aktiviert: Cronjob wird gemäß Zeitplan ausgeführt

  • Deaktiviert: Cronjob wird pausiert (Standard: aktiviert)

Ausführungseinstellungen

Umgebung

Die Umgebung bestimmt, wodurch der Cronjob ausgelöst wird:

Umgebung Auslöser Empfohlen für

Skript Server-Cronjob Zeitkritische und regelmäßige Aufgaben

Frontend Seitenaufruf im Frontend Unkritische, seltene Aufgaben

Backend Aktivität im Backend Administrative Aufgaben

Wichtig: Die Umgebung Skript sollte nicht gleichzeitig mit Frontend oder Backend aktiviert werden (außer zu Testzwecken).

Ausführungszeitpunkt

Nur für Frontend/Backend-Umgebung relevant:

  • Beginn: Vor dem Seitenaufbau (kann zu Verzögerungen führen)

  • Ende: Nach dem Seitenaufbau (empfohlen)

Intervall

Definiert die Häufigkeit der Ausführung:

  • Minütlich, stündlich, täglich, wöchentlich, monatlich

  • Benutzerdefinierte Intervalle möglich

  • Standard: Täglich nach 0:00 Uhr

Funktionalität

Typ

Verfügbare Standard-Typen:

  • PHP-Code: Direkter PHP-Code

  • PHP-Callback: Funktions- oder Methodenaufruf

  • URL-Aufruf: HTTP-Request an eine URL

AddOns können weitere Typen bereitstellen:

  • Datenbankexport (Backup-AddOn)

  • Search it: Reindexieren (Search it-AddOn)

  • Weitere projektspezifische Typen

Typspezifische Parameter

Je nach gewähltem Typ stehen unterschiedliche Eingabemöglichkeiten zur Verfügung:

PHP-Code:

// Beispiel: Cache leeren rex_delete_cache(); echo "Cache wurde geleert"; ``n

PHP-Callback:

// Beispiel: Statische Methode MyClass::myMethod ``n

URL-Aufruf:

https://example.com/webhook ``n

Ausführungsumgebungen im Detail

Skript-Umgebung (empfohlen)

Vorteile:

  • Unabhängig von Seitenaufrufen

  • Zuverlässige, zeitgenaue Ausführung

  • Keine Performance-Beeinträchtigung für Besucher

  • Ideal für ressourcenintensive Aufgaben

Nachteile:

  • Erfordert Zugriff auf Server-Cronjobs

  • Keine Session-Informationen verfügbar

Frontend-Umgebung

Vorteile:

  • Kein Server-Zugriff erforderlich

  • Zugriff auf Frontend-Session

Nachteile:

  • Abhängig von Besucheraufkommen

  • Kann Ladezeiten beeinflussen

  • Unregelmäßige Ausführung möglich

Backend-Umgebung

Vorteile:

  • Manuelle Ausführung möglich

  • Zugriff auf Backend-Session

  • Gut für administrative Aufgaben

Nachteile:

  • Nur bei Backend-Aktivität

  • Nicht für zeitkritische Aufgaben geeignet

Server-Cronjob einrichten

Für die Skript-Umgebung muss ein Server-Cronjob konfiguriert werden:

1. Crontab öffnen:

crontab -e ``n

2. Cronjob hinzufügen:

`# Jede Minute ausführen (empfohlen)

          • /usr/bin/php /pfad/zu/redaxo/bin/console cronjob:run

Alle 5 Minuten ausführen

*/5 * * * * /usr/bin/php /pfad/zu/redaxo/bin/console cronjob:run

Stündlich ausführen

0 * * * * /usr/bin/php /pfad/zu/redaxo/bin/console cronjob:run `n

Wichtig: Das Server-Intervall sollte kleiner oder gleich dem kleinsten REDAXO-Cronjob-Intervall sein.

Eigene Cronjob-Typen entwickeln

Grundlagen

Um einen eigenen Cronjob-Typ zu erstellen, muss eine PHP-Klasse von rex_cronjob abgeleitet werden. Diese definiert die Funktionalität und stellt Konfigurationsfelder bereit.

Schritt-für-Schritt-Anleitung

1. Cronjob-Klasse erstellen

Erstelle eine PHP-Datei in /redaxo/src/addons/mein_addon/lib/cronjob/:

`<?php

class rex_cronjob_mein_typ extends rex_cronjob { public function execute() { try { // Hauptfunktionalität implementieren $this->setMessage(‘Erfolgreich ausgeführt’); return true; } catch (Exception $e) { $this->setMessage(‘Fehler: ‘ . $e->getMessage()); return false; } }

public function getTypeName()
{
    return 'Mein Cronjob-Typ';
}

public function getParamFields()
{
    return [
        [
            'label' => 'Parameter',
            'name' => 'mein_parameter',
            'type' => 'text',
            'notice' => 'Beschreibung des Parameters'
        ]
    ];
} }` ``n

2. Typ registrieren

In der boot.php des AddOns:

<?php if (rex_addon::get('cronjob')->isAvailable()) { rex_cronjob_manager::registerType('rex_cronjob_mein_typ'); } ``n

Praktisches Beispiel

Newsletter-Abonnenten-Benachrichtigung:

`<?php

class rex_cronjob_subscriber_notification extends rex_cronjob { public function execute() { $email = $this->getParam(‘notification_email’); $table = $this->getParam(‘subscriber_table’, ‘rex_newsletter_user’); $last_check = $this->getParam(‘last_check_timestamp’, 0);

    if (empty($email)) {
        $this->setMessage('Keine E-Mail-Adresse konfiguriert');
        return false;
    }

    try {
        // Neue Abonnenten finden
        $sql = rex_sql::factory();
        $sql->setQuery(
            "SELECT * FROM {$table} 
             WHERE createdate > :last_check 
             AND status = 1",
            ['last_check' => date('Y-m-d H:i:s', $last_check)]
        );

        $new_subscribers = $sql->getArray();

        if (count($new_subscribers) > 0) {
            // E-Mail senden
            $this->sendNotification($email, $new_subscribers);
            $this->setMessage(count($new_subscribers) . ' neue Abonnenten gefunden');
        } else {
            $this->setMessage('Keine neuen Abonnenten');
        }

        // Zeitstempel aktualisieren
        $this->setParam('last_check_timestamp', time());

        return true;

    } catch (Exception $e) {
        $this->setMessage('Fehler: ' . $e->getMessage());
        return false;
    }
}

private function sendNotification($email, $subscribers)
{
    if (!rex_addon::get('phpmailer')->isAvailable()) {
        throw new Exception('PHPMailer nicht verfügbar');
    }

    $mail = new rex_mailer();
    $mail->addAddress($email);
    $mail->Subject = 'Neue Newsletter-Abonnenten: ' . count($subscribers);

    $body = "Neue Abonnenten:\n\n";
    foreach ($subscribers as $subscriber) {
        $body .= "- {$subscriber['email']} ({$subscriber['createdate']})\n";
    }

    $mail->Body = $body;

    if (!$mail->send()) {
        throw new Exception('E-Mail-Versand fehlgeschlagen');
    }
}

public function getTypeName()
{
    return 'Newsletter-Abonnenten-Benachrichtigung';
}

public function getParamFields()
{
    return [
        [
            'label' => 'Benachrichtigungs-E-Mail',
            'name' => 'notification_email',
            'type' => 'text',
            'attributes' => ['type' => 'email'],
            'notice' => 'E-Mail für Benachrichtigungen'
        ],
        [
            'label' => 'Tabelle',
            'name' => 'subscriber_table',
            'type' => 'text',
            'default' => 'rex_newsletter_user'
        ],
        [
            'name' => 'last_check_timestamp',
            'type' => 'hidden',
            'default' => 0
        ]
    ];
} }` ``n

Parameterfeld-Typen

Text-Eingabefeld

[ 'label' => 'Textfeld', 'name' => 'text_param', 'type' => 'text', 'default' => 'Standardwert', 'notice' => 'Hilfetext', 'attributes' => [ 'placeholder' => 'Platzhalter', 'maxlength' => 255, 'required' => 'required' ] ] ``n

Textarea

[ 'label' => 'Mehrzeiliger Text', 'name' => 'textarea_param', 'type' => 'textarea', 'attributes' => ['rows' => 10, 'cols' => 50] ] ``n

Auswahlfeld (Select)

[ 'label' => 'Auswahl', 'name' => 'select_param', 'type' => 'select', 'options' => [ 'option1' => 'Erste Option', 'option2' => 'Zweite Option' ], 'default' => 'option1' ] ``n

Checkbox (als Select)

[ 'label' => 'Aktiviert', 'name' => 'checkbox_param', 'type' => 'select', 'options' => ['0' => 'Nein', '1' => 'Ja'], 'default' => '1' ] ``n

Verstecktes Feld

[ 'name' => 'hidden_param', 'type' => 'hidden', 'default' => 'interner_wert' ] ``n

Erweiterte Funktionen

Umgebungen einschränken

public function getEnvironments() { // Nur in Skript-Umgebung verfügbar return ['script']; } ``n

Parameter zur Laufzeit ändern

`public function execute() { $counter = (int) $this->getParam(‘counter’, 0); $counter++;

// Arbeit durchführen...

// Counter für nächste Ausführung speichern
$this->setParam('counter', $counter);

$this->setMessage("Ausführung #{$counter} erfolgreich");
return true; }` ``n

Debugging und Logging

`public function execute() { $debug = [];

try {
    // Schritt 1
    $debug[] = 'Daten geladen';

    // Schritt 2
    $debug[] = 'Verarbeitung abgeschlossen';

    // Bei Erfolg
    $this->setMessage('Erfolgreich: ' . implode(' > ', $debug));
    return true;

} catch (Exception $e) {
    // Bei Fehler
    $this->setMessage(
        'Fehler nach: ' . implode(' > ', $debug) . 
        ' - ' . $e->getMessage()
    );
    return false;
} }` ``n

API-Referenz

rex_cronjob Klasse

Abstrakte Methoden (müssen implementiert werden)

Methode Rückgabe Beschreibung

execute() bool Hauptfunktionalität des Cronjobs

Optionale Methoden

Methode Rückgabe Beschreibung

getTypeName() string Anzeigename im Backend

getParamFields() array Konfigurationsfelder

getEnvironments() array Verfügbare Umgebungen

Parameter-Methoden

Methode Parameter Beschreibung

setParam($key, $value) string, mixed Einzelnen Parameter setzen

getParam($key, $default) string, mixed Parameter abrufen

setParams($params) array Alle Parameter setzen

getParams()

Alle Parameter abrufen

Nachrichten-Methoden

Methode Parameter Beschreibung

setMessage($message) string Status-Nachricht setzen

getMessage()

Nachricht abrufen

hasMessage()

Prüft ob Nachricht vorhanden

rex_cronjob_manager Klasse

Methode Parameter Beschreibung

registerType($class) string Neuen Typ registrieren

getTypes()

Alle Typen abrufen

factory($class) string Instanz erstellen

Parameterfeld-Definitionen

Grundstruktur

[ 'label' => 'Bezeichnung', // Pflicht: Anzeigename 'name' => 'parameter_name', // Pflicht: Interner Name 'type' => 'text', // Pflicht: Feldtyp 'default' => '', // Optional: Standardwert 'notice' => '', // Optional: Hilfetext 'attributes' => [], // Optional: HTML-Attribute 'options' => [] // Nur für type='select' ] ``n

HTML5-Eingabetypen

Über das attributes Array können HTML5-Typen gesetzt werden:

`// E-Mail [‘attributes’ => [‘type’ => ‘email’]]

// Nummer [‘attributes’ => [‘type’ => ‘number’, ‘min’ => 0, ‘max’ => 100]]

// Datum [‘attributes’ => [‘type’ => ‘date’]]

// URL [‘attributes’ => [‘type’ => ‘url’]] `n

Best Practices

Performance

  • Skript-Umgebung verwenden für zeitkritische Aufgaben

  • Ressourcenintensive Aufgaben in kleinere Teile aufteilen

  • Timeouts beachten und ggf. erhöhen

  • Datenbankabfragen optimieren (Indizes nutzen)

Fehlerbehandlung

  • Try-Catch-Blöcke verwenden

  • Aussagekräftige Fehlermeldungen zurückgeben

  • Logging für kritische Operationen implementieren

  • Transaktionen bei Datenbankoperationen nutzen

Sicherheit

  • Eingaben validieren bei Parametern

  • Berechtigungen prüfen bei sensiblen Operationen

  • Prepared Statements für Datenbankabfragen

  • Externe APIs mit Timeouts absichern

Wartbarkeit

  • Sprechende Namen für Cronjobs und Parameter

  • Dokumentation in Beschreibungsfeldern

  • Versionierung bei eigenen Typen

  • Internationalisierung über Sprachdateien

Troubleshooting

Cronjob wird nicht ausgeführt

Mögliche Ursachen:

  • Cronjob ist deaktiviert

  • Server-Cronjob nicht eingerichtet

  • Falsches Intervall konfiguriert

  • PHP-Fehler im Code

Lösungsansätze:

  • Status prüfen (aktiviert?)

  • Server-Cronjob testen: /pfad/zu/redaxo/bin/console cronjob:run

  • Error-Log prüfen

  • Manuell im Backend ausführen (Test)

Performance-Probleme

Optimierungen:

  • Große Datenmengen in Batches verarbeiten

  • Datenbankabfragen mit LIMIT versehen

  • Caching implementieren

  • Auf Skript-Umgebung umstellen

E-Mail-Versand funktioniert nicht

Prüfpunkte:

  • PHPMailer-AddOn installiert und konfiguriert?

  • SMTP-Einstellungen korrekt?

  • Spam-Filter prüfen

  • Test-Mail über PHPMailer-AddOn senden

Debugging aktivieren

`public function execute() { // Debug-Modus if ($this->getParam(‘debug_mode’)) { rex_logger::factory()->log(‘info’, ‘Cronjob Start’, [ ‘params’ => $this->getParams(), ‘time’ => date(‘Y-m-d H:i:s’) ]); }

// Cronjob-Logik...

return true; }` ``n