Scheduled Tasks
Tool-Aufrufe, die automatisch in festen Intervallen laufen.
Ein Scheduled Task ist eine Tool-Ausführung ohne Benutzer. Du konfigurierst, welches Tool wann mit welchen Args laufen soll — die Plattform tut es dann in der Wiederholfrequenz automatisch.
Wofür?
Klassiker:
- Jede Nacht neue E-Mails aus der Mailbox klassifizieren
- Alle 10 Minuten neue Bestellungen prüfen und bei bestimmten Kriterien auslösen
- Wöchentlich einen Report bauen und per E-Mail versenden
- Alle 2 Stunden OAuth-Tokens refreshen, die sonst ablaufen würden
Datei
In deinem Workspace scheduled.php:
<?php
return [
'scheduled' => [
'process_new_orders' => [
'enabled' => true,
'tool' => 'processNewOrders',
'interval' => '5min',
'args' => ['dryRun' => false],
],
'daily_report' => [
'enabled' => true,
'tool' => 'sendDailyReport',
'interval' => '09:00',
'args' => ['recipients' => ['chef@kunde.de']],
],
'refresh_tokens' => [
'enabled' => true,
'tool' => 'refreshAllOauthTokens',
'interval' => '2h',
],
],
];
Felder
| Feld | Bedeutung |
|---|---|
enabled |
true / false — schnelles An/Aus ohne Code-Löschen |
tool |
Name eines Tools, das ausgeführt werden soll |
interval |
Wiederholintervall (5min, 2h) oder feste Tageszeit (09:00) — siehe unten |
args |
Argument-Map, die dem Tool übergeben wird |
max_runtime |
Optional: maximale Laufzeit in Minuten (Default 60). Solange ein Lauf jünger ist, startet kein zweiter Lauf desselben Tasks, und er wird nicht als hängend abgebrochen. Erst danach gilt er als abgestürzt (Status error) und der Task darf wieder starten. Erlaubt sind 5–240 Minuten; kleinere/größere Werte werden auf diese Grenzen gesetzt (Obergrenze plattformweit über Platform.scheduled.max_runtime_cap). |
lane |
Optional: 'long' für Langläufer (mehrere Minuten). Der normale Lauf (run_scheduled_tasks, gleich --lane=default) überspringt solche Tasks; ein zweiter Cron-Aufruf run_scheduled_tasks --tenant=<code> --lane=long im Hintergrund führt nur sie aus. So hält ein langer Task die kurzen (Inbox-Import, Health-Check) nicht auf. Ohne lane (oder mit einem anderen Wert) bleibt der Task in der Standard-Spur. Doppelstarts verhindert der Lock pro Task (max_runtime), unabhängig von der Spur. --task <name> ohne --lane startet den Task in jeder Spur. Achtung: Ohne Cron-Zeile für --lane=long laufen long-Tasks gar nicht. |
Achtung:
intervaldeckt beide Fälle ab (Wiederholung + feste Uhrzeit). Ein separates Feldat_timegibt es nicht — es wird still ignoriert und der Task läuft dann bei jedem Cron-Tick. Wenn du "täglich um 07:00" willst:'interval' => '07:00'.
Intervall-Syntax (interval)
Periodische Wiederholung:
| Format | Bedeutung |
|---|---|
5min |
alle 5 Minuten |
30min |
alle 30 Minuten |
2h |
alle 2 Stunden |
6h |
alle 6 Stunden |
1d |
einmal pro Tag (24h-Rhythmus) |
Intervalle laufen ab dem Zeitpunkt, an dem der Task zum ersten Mal getriggert wurde.
Uhrzeit-Syntax (interval im HH:MM-Format)
Für täglich wiederkehrende Läufe zu einer festen Uhrzeit: gleiches Feld
interval, aber Wert im HH:MM-Format:
'interval' => '09:00', // jeden Morgen um 9 Uhr
'interval' => '03:30', // jede Nacht um 3:30
Zeiten beziehen sich auf die Serverzeit (typisch Europe/Berlin — beim Betreiber prüfen).
Tool-Anforderungen
Das aufgerufene Tool …
- … muss Handler-basiert oder API-basiert definiert sein (genau wie Chat-Tools)
- … bekommt
argsaus der Scheduled-Task-Definition - … sollte idempotent sein — kann passieren, dass ein Lauf doppelt ausgeführt wird (z. B. nach Server-Neustart)
- … sollte schnell sein — Long-Running-Jobs (>60s) lieber in mehrere kleinere zerlegen
Testen
Ein Scheduled Task ist technisch „nur" ein Tool-Aufruf. Testen wie jedes andere Tool:
tm test-tool processNewOrders
# mit den Args aus scheduled.php und dry-run:
tm test-tool processNewOrders dryRun=true --dry-run
Beobachten
Wenn ein Scheduled Task live läuft:
tm monitor
Scheduled-Runs erscheinen mit Typ CRON:
03:00:05 [ OK ] CRON processNewOrders 2.1s
10:00:03 [ OK ] CRON sendDailyReport 5.4s
Volle Logs:
tm logs --lines 500
Protokoll-Volumen und Aufbewahrung
Jeder Tool-Aufruf — auch jeder Sub-Aufruf per $ctx['tool']() — ist eine Zeile im Ausführungsprotokoll (task_executions, verschachtelte Aufrufe mit parent_id auf den Aufrufer). Ein Lauf, der ein Sub-Tool 150-mal aufruft, schreibt 150 Zeilen. Für solche hochfrequenten Sub-Tools gibt es task_log (üblicherweise in scheduled.php):
'task_log' => [
// Erfolgreiche Sub-Aufrufe in geplanten Läufen nur als eine Sammelzeile
// pro Lauf (business_metrics: aggregated, calls, duration_ms_max).
// Fehler und Root-Aufrufe werden immer einzeln protokolliert.
'aggregate_tools' => ['updateSalesOrderComment', 'readFromGoogleSheet'],
'aggregate_entry_types' => ['scheduled'], // Default
// Aufbewahrung in Tagen (Default und Obergrenze 90)
'retention_days' => 90,
// Kürzer für einzelne Tools/Eintrittsarten; kürzeste passende Regel gewinnt.
'retention_rules' => [
['days' => 14, 'entry_types' => ['scheduled'], 'tools' => ['updateSalesOrderComment']],
],
],
Aufgeräumt wird täglich um 04:00 (bin/cake prune_task_executions, höchstens 200.000 Zeilen pro Lauf). --dry-run zeigt pro Workspace und Regel, was gelöscht würde. Der Workspace kann die Aufbewahrung nur verkürzen, nicht über die Plattform-Grenze verlängern.
Grenzen für den Audit-Trail (gelten unabhängig von task_log):
- Einträge von API-Key-, Public-API-, API- und Webhook-Läufen, Builder-Läufen sowie
writeTenantConfig/deleteTenantConfigbleiben mindestens 90 Tage — auch bei kürzererretention_daysoder passenderretention_rules. - Zusammengefasst werden nur geplante Läufe (
aggregate_entry_typesnurscheduled/cron, andere Werte werden ignoriert);writeTenantConfig/deleteTenantConfignie.
Deaktivieren
'daily_report' => [
'enabled' => false, // ← das reicht
// ... Rest bleibt unverändert ...
],
Bewusst enabled-Flag statt Code löschen — so bleibt die Definition dokumentiert und du kannst sie per Toggle reaktivieren.
Ausführung durch die Plattform
Die Aktivierung und Ausführung übernimmt die Betriebsseite automatisch — du musst nichts einrichten. Sobald scheduled.php synchronisiert ist, greift die Plattform die Intervalle auf und startet die Runs.
Caveats
- Keine Garantien auf Minutengenauigkeit. Bei hoher Last oder kurzen Ausfällen kann ein Run ein paar Sekunden später starten.
- Kein Benutzer-Kontext — Tools, die Session oder Upload-Kontext brauchen, funktionieren hier nicht. Nutze Tools, die sich nur auf Args und Server-State stützen.
- Fehlschläge werden geloggt, nicht retried. Wenn ein Run fehlschlägt, läuft der nächste wie geplant weiter. Baue bei Bedarf eigene Retry-Logik in den Handler.