Skip to main content

Retry Logic

Retry-Logik ermöglicht es, fehlgeschlagene Operationen automatisch erneut zu versuchen. Dies ist entscheidend für robuste Workflows, die auch bei temporären Fehlern zuverlässig funktionieren.

Warum Retry-Logik?

Temporäre Fehler sind häufig:
  • Netzwerk-Timeouts
  • API-Rate Limits (429)
  • Server-Überlastung (503)
  • Temporäre Verbindungsprobleme

Ohne Retry

Ein Fehler = Workflow fehlgeschlagen
  • Manuelle Intervention erforderlich
  • Datenverlust möglich
  • Unzuverlässige Automatisierung

Mit Retry

Automatische Wiederholung
  • Temporäre Fehler werden überwunden
  • Höhere Erfolgsrate
  • Weniger manuelle Intervention

Retry-Strategien

Exponential Backoff

Die empfohlene Strategie für die meisten Fälle:
Exponential Backoff erhöht Wartezeit exponentiell:
Versuch 1: Sofort
Versuch 2: Nach 1 Sekunde
Versuch 3: Nach 2 Sekunden
Versuch 4: Nach 4 Sekunden
Versuch 5: Nach 8 Sekunden
Vorteile:
  • Gibt Server Zeit zur Erholung
  • Reduziert Last bei Überlastung
  • Standard-Pattern für APIs
Exponential Backoff in Function Node:
const maxRetries = 5;
const baseDelay = 1000; // 1 Sekunde
const retryCount = $workflow.staticData.retryCount || 0;

if (retryCount < maxRetries) {
  const delay = Math.pow(2, retryCount) * baseDelay;
  
  // Wartezeit einbauen
  await new Promise(resolve => setTimeout(resolve, delay));
  
  // Retry-Count erhöhen
  $workflow.staticData.retryCount = retryCount + 1;
  
  // Operation erneut versuchen
  return $input.all();
} else {
  // Max Retries erreicht
  throw new Error(`Operation failed after ${maxRetries} retries`);
}

Linear Backoff

Konstante Wartezeit zwischen Versuchen:
const maxRetries = 5;
const delay = 2000; // 2 Sekunden konstant
const retryCount = $workflow.staticData.retryCount || 0;

if (retryCount < maxRetries) {
  await new Promise(resolve => setTimeout(resolve, delay));
  $workflow.staticData.retryCount = retryCount + 1;
  return $input.all();
}

Jitter hinzufügen

Zufällige Variation verhindert Thundering Herd:
const baseDelay = 1000;
const retryCount = $workflow.staticData.retryCount || 0;
const exponentialDelay = Math.pow(2, retryCount) * baseDelay;

// Jitter: ±25% zufällige Variation
const jitter = exponentialDelay * 0.25 * (Math.random() * 2 - 1);
const delay = exponentialDelay + jitter;

await new Promise(resolve => setTimeout(resolve, delay));

Retry-Implementierung

Error Trigger Node

Verwenden Sie Error Trigger für Retry-Logik:
Typischer Retry-Workflow:
Process Node → Error Trigger → Retry Logic → Process Node
// Schritt 1: Operation versuchen
HTTP Request → API Call

// Schritt 2: Bei Fehler
Error Trigger → Retry Logic

// Schritt 3: Retry durchführen
Retry Logic → HTTP Request (erneut)
Error Trigger einrichten:
{
  "errorTypes": [
    "node",
    "workflow"
  ],
  "options": {
    "includeExecutionData": true
  }
}

Retry-Logik mit Function Node

Vollständige Retry-Implementierung:
// Konfiguration
const MAX_RETRIES = 5;
const BASE_DELAY = 1000; // 1 Sekunde
const MAX_DELAY = 30000; // 30 Sekunden Maximum

// Retryable Error Codes
const RETRYABLE_ERRORS = [429, 503, 504, 'ETIMEDOUT', 'ECONNRESET'];

// Retry-Count aus Workflow-State
const retryCount = $workflow.staticData.retryCount || 0;
const lastError = $workflow.staticData.lastError || null;

// Prüfe ob Fehler retryable ist
function isRetryable(error) {
  if (!error) return false;
  
  // HTTP Status Codes
  if (error.statusCode && RETRYABLE_ERRORS.includes(error.statusCode)) {
    return true;
  }
  
  // Error Codes
  if (error.code && RETRYABLE_ERRORS.includes(error.code)) {
    return true;
  }
  
  // Error Messages
  if (error.message) {
    const message = error.message.toLowerCase();
    if (message.includes('timeout') || 
        message.includes('rate limit') ||
        message.includes('temporary')) {
      return true;
    }
  }
  
  return false;
}

// Prüfe ob Retry möglich ist
if (retryCount < MAX_RETRIES && isRetryable(lastError)) {
  // Exponential Backoff berechnen
  const exponentialDelay = Math.min(
    Math.pow(2, retryCount) * BASE_DELAY,
    MAX_DELAY
  );
  
  // Jitter hinzufügen (±10%)
  const jitter = exponentialDelay * 0.1 * (Math.random() * 2 - 1);
  const delay = exponentialDelay + jitter;
  
  // Retry-Count erhöhen
  $workflow.staticData.retryCount = retryCount + 1;
  $workflow.staticData.retryDelay = delay;
  
  // Wartezeit einbauen
  await new Promise(resolve => setTimeout(resolve, delay));
  
  // Original-Input zurückgeben für Retry
  return $input.all();
} else {
  // Max Retries erreicht oder nicht retryable
  throw new Error(
    `Operation failed after ${retryCount} retries. ` +
    `Last error: ${lastError?.message || 'Unknown'}`
  );
}

Retryable vs. Non-Retryable Fehler

Retryable Fehler

Diese Fehler sollten wiederholt werden:

429 Too Many Requests

Rate Limit erreicht - Wartezeit hilft

503 Service Unavailable

Temporäre Server-Überlastung

504 Gateway Timeout

Timeout - möglicherweise temporär

ECONNRESET

Verbindung zurückgesetzt - Netzwerkproblem

ETIMEDOUT

Timeout - möglicherweise temporär

500 Internal Server Error

Manchmal temporär (abhängig von API)

Non-Retryable Fehler

Diese Fehler sollten NICHT wiederholt werden:

400 Bad Request

Ungültige Anfrage - wird nicht besser

401 Unauthorized

Authentifizierung fehlgeschlagen

403 Forbidden

Keine Berechtigung

404 Not Found

Ressource existiert nicht

422 Unprocessable Entity

Validierungsfehler

Retry-Patterns

Pattern 1: Node-Level Retry

Retry direkt im Node konfigurieren:
{
  "method": "POST",
  "url": "https://api.example.com/endpoint",
  "options": {
    "retry": {
      "maxRetries": 3,
      "retryOnFail": true,
      "retryDelay": 1000
    }
  }
}

Pattern 2: Workflow-Level Retry

Retry für gesamten Workflow-Bereich:
Workflow-Bereich → Error Trigger → Retry Logic → Workflow-Bereich

Pattern 3: Conditional Retry

Retry nur bei bestimmten Bedingungen:
const error = $json.error;
const retryCount = $workflow.staticData.retryCount || 0;

// Retry nur bei Rate Limit
if (error.statusCode === 429 && retryCount < 3) {
  // Wartezeit basierend auf Retry-After Header
  const retryAfter = parseInt(error.headers['retry-after'] || '60');
  await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
  
  $workflow.staticData.retryCount = retryCount + 1;
  return $input.all();
}

// Andere Fehler nicht retryen
throw error;

Retry mit Rate Limit Handling

Retry-After Header verwenden

Respektieren Sie Retry-After Header:
const response = $json;
const retryAfter = response.headers['retry-after'];

if (response.statusCode === 429 && retryAfter) {
  // Wartezeit aus Header verwenden
  const delay = parseInt(retryAfter) * 1000;
  
  await new Promise(resolve => setTimeout(resolve, delay));
  
  // Erneut versuchen
  return $input.all();
}

Best Practices

Max Retries begrenzen

Setzen Sie ein Maximum für Retries:
  • Zu viele Retries können Kosten erhöhen
  • Unendliche Loops vermeiden
  • Typisch: 3-5 Retries

Exponential Backoff

Verwenden Sie Exponential Backoff:
  • Gibt Server Zeit zur Erholung
  • Reduziert Last
  • Standard-Pattern

Jitter hinzufügen

Fügen Sie Jitter hinzu:
  • Verhindert Thundering Herd
  • Verteilt Last gleichmäßiger
  • ±10-25% Variation

Retryable Errors identifizieren

Unterscheiden Sie retryable/non-retryable:
  • Nicht alle Fehler sollten retryed werden
  • 4xx Fehler meist nicht retryable
  • 5xx Fehler oft retryable

Logging

Loggen Sie Retry-Versuche:
  • Retry-Count tracken
  • Fehler protokollieren
  • Performance überwachen

Timeout berücksichtigen

Setzen Sie angemessene Timeouts:
  • Zu kurze Timeouts = unnötige Retries
  • Zu lange Timeouts = langsame Fehlerbehandlung
  • Balance finden

Monitoring und Alerting

Retry-Metriken überwachen

Wichtige Metriken:
{
  "retryRate": "Anzahl Retries / Gesamt-Requests",
  "successAfterRetry": "Erfolgreiche Retries",
  "maxRetriesReached": "Anzahl fehlgeschlagener Retries",
  "averageRetryDelay": "Durchschnittliche Wartezeit",
  "retryableErrors": {
    "429": "Anzahl Rate Limit Fehler",
    "503": "Anzahl Service Unavailable",
    "504": "Anzahl Gateway Timeout"
  }
}

Alerting bei häufigen Retries

Alert wenn Retry-Rate zu hoch:
const retryRate = $workflow.staticData.retryRate || 0;

if (retryRate > 0.1) { // Mehr als 10% Retries
  // Alert senden
  return [{
    json: {
      alert: true,
      message: `High retry rate: ${retryRate * 100}%`,
      action: "investigate"
    }
  }];
}

Checkliste

  • Retry-Logik ist implementiert
  • Max Retries ist begrenzt (3-5)
  • Exponential Backoff wird verwendet
  • Jitter ist hinzugefügt
  • Retryable/Non-Retryable Fehler werden unterschieden
  • Retry-After Header wird respektiert
  • Retry-Versuche werden geloggt
  • Retry-Metriken werden überwacht
  • Alerting bei hoher Retry-Rate

Praktisches Beispiel

API-Call mit Retry-Logik

Vollständiges Beispiel:
1

API-Call durchführen

HTTP Request → API Call
2

Error Trigger konfigurieren

Error Trigger → Bei Fehler aktivieren
3

Retry-Logik implementieren

// Prüfe ob retryable
if (isRetryable($json.error) && retryCount < 5) {
  // Exponential Backoff
  const delay = Math.pow(2, retryCount) * 1000;
  await sleep(delay);
  
  // Retry
  return $input.all();
}
4

Erfolgreiche Operation

// Retry-Count zurücksetzen
$workflow.staticData.retryCount = 0;

Nächste Schritte


Wichtig: Retry-Logik sollte immer mit einem Maximum begrenzt werden, um unendliche Loops zu vermeiden. Dokumentieren Sie Ihre Retry-Strategie für zukünftige Wartung.