Erweiterte Konzepte
Dieses Kapitel behandelt fortgeschrittene Features des External-Task-Systems im App-SDK.
AbortSignal
Der dritte Parameter der Handler-Funktion ist ein AbortSignal. Dieses Signal wird ausgelöst, wenn ein Boundary Event den External Service Task im Prozess abbricht — beispielsweise ein Timer-Boundary-Event oder ein Signal-Boundary-Event.
Grundlegendes Beispiel
export const config = {
lockDuration: 5000,
};
export default async function longTask(
payload: any,
_task: any,
signal: AbortSignal
) {
signal.addEventListener('abort', () => {
console.log('Task abgebrochen — Aufräumarbeiten durchführen');
}, { once: true });
await langwierigeOperation(signal);
if (signal.aborted) return;
return { result: 'fertig' };
}Delay mit AbortSignal
Ein häufiges Muster: eine Wartezeit, die bei Abbruch sofort beendet wird.
function delay(ms: number, signal?: AbortSignal) {
return new Promise<void>((resolve, reject) => {
if (signal?.aborted) {
reject(new Error('Aborted'));
return;
}
const timer = setTimeout(resolve, ms);
signal?.addEventListener('abort', () => {
clearTimeout(timer);
reject(new Error('Aborted'));
}, { once: true });
});
}Zusammenhang mit lockDuration
Die lockDuration bestimmt, wie schnell ein Abbruch erkannt wird:
- Die Engine prüft bei jeder Lock-Verlängerung, ob der Task noch aktiv ist
- Eine niedrige
lockDuration(z.B.5000) ermöglicht schnelle Abbrüche - Eine hohe
lockDuration(z.B.300000) verzögert die Erkennung
Für Tasks mit Boundary Events empfiehlt sich eine lockDuration von 5000–10000 ms.
Lebenszyklus eines External Tasks
Worker-Startup und IPC-Kommunikation
Das App SDK startet pro external_task.ts-Datei einen eigenen Node.js-Kindprozess. Die Kommunikation zwischen Hauptprozess (Adapter) und Kindprozess (Worker) laeuft ueber IPC:
IPC-Nachrichten:
| Action | Richtung | Beschreibung |
|---|---|---|
create | Adapter → Worker | Initialer Start: Übergibt Topic, Identity und transpilierten Handler-Code |
restart | Adapter → Worker | Hot-Reload: Stoppt den alten Worker und startet mit neuem Code (gleiche Worker-ID) |
updateIdentity | Adapter → Worker | Aktualisiert den Auth-Token auf dem laufenden Worker |
Resilienz
Das App-SDK bietet mehrere Mechanismen, um External Task Worker zuverlässig zu betreiben.
Fehlerbehandlung und Restart-Strategie
Worker-Level (Kindprozess)
- Bei Verbindungsfehlern (ECONNREFUSED, ECONNRESET, ETIMEDOUT, ENOTFOUND, EAI_AGAIN, Socket Hang Up) versucht der Worker bis zu 6 Reconnects mit exponentiellem Backoff (1s → 2s → 4s → 8s → 16s → 30s max).
- Die Anzahl der Retries ist über die Umgebungsvariable
PROCESSCUBE_APP_SDK_ETW_RETRYkonfigurierbar. - Nach Ausschöpfung der Retries beendet sich der Worker mit Exit Code 3.
- Bei unbehandelten Exceptions beendet sich der Worker mit Exit Code 4.
Adapter-Level (Hauptprozess)
- Erkennt der Adapter einen Worker-Exit mit Code 3 oder 4, wird ein Neustart versucht.
- Maximal 6 Neustarts innerhalb eines 5-Minuten-Fensters sind erlaubt.
- Die Backoff-Zeiten steigen exponentiell: 1s → 2s → 4s → 8s → 16s → 30s.
- Wird das Limit erreicht, bleibt der Worker gestoppt — ein manueller Eingriff (z.B. App-Neustart) ist nötig.
- Nach Ablauf des 5-Minuten-Fensters wird der Zähler zurückgesetzt.
Token-Management
- Der Token wird bei 85% seiner Lebensdauer automatisch erneuert.
- Alle aktiven Worker erhalten den neuen Token per IPC-Nachricht.
- Der initiale Token-Abruf hat 10 Versuche mit exponentiellem Backoff (max. 30s).
- Der periodische Token-Refresh versucht es unbegrenzt mit Backoff (max. 60s).
- Ist keine Authority konfiguriert, wird eine Dummy-Identity verwendet (für lokale Entwicklung ohne Auth).
Hot Reload
Das App-SDK überwacht das App-Verzeichnis mit Chokidar . Änderungen an external_task.ts-Dateien werden automatisch erkannt:
| Ereignis | Aktion |
|---|---|
| Datei hinzugefügt | Neuer Worker wird gestartet |
| Datei geändert | Worker wird mit neuem Code neu gestartet (Worker-ID bleibt erhalten) |
| Datei gelöscht | Worker wird gestoppt |
Beim Neustart durch Code-Änderungen bleibt die Worker-ID erhalten. Laufende Tasks werden sauber beendet, bevor der neue Code aktiviert wird.
Route Groups
Next.js Route Groups (Verzeichnisse in runden Klammern) werden aus dem Topic entfernt:
| Dateipfad | Topic |
|---|---|
app/(workers)/send_email/external_task.ts | send_email |
app/(email)/filter/external_task.ts | filter |
app/(group1)/(group2)/task/external_task.ts | task |
So können External Tasks organisiert werden, ohne das Topic zu beeinflussen:
app/
├── (email-workers)/
│ ├── filter_email/
│ │ └── external_task.ts → Topic: filter_email
│ ├── forward_email/
│ │ └── external_task.ts → Topic: forward_email
│ └── delete_email/
│ └── external_task.ts → Topic: delete_email
├── (order-workers)/
│ └── process_order/
│ └── external_task.ts → Topic: process_order
└── dashboard/
└── page.tsx → Route: /dashboardTranspilation
External Task Dateien werden automatisch mit esbuild transpiliert, bevor sie als Worker-Prozess gestartet werden:
- Plattform: Node.js
- Target:
node18 - Format: CommonJS
- Bundling: Aktiviert (Dependencies werden eingebunden)
- Externe Pakete:
@opentelemetry/apiwird nicht gebündelt
Das bedeutet: TypeScript, moderne ES-Syntax und Imports von npm-Paketen funktionieren direkt, ohne zusätzliche Build-Konfiguration.