

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

# Bewährte Methoden für langlebige Lambda-Funktionen
<a name="durable-best-practices"></a>

Dauerhafte Funktionen verwenden ein auf Wiedergabe basierendes Ausführungsmodell, das andere Muster erfordert als herkömmliche Lambda-Funktionen. Folgen Sie diesen bewährten Methoden, um zuverlässige und kostengünstige Workflows zu erstellen.

## Schreiben Sie deterministischen Code
<a name="durable-determinism"></a>

Während der Wiedergabe wird Ihre Funktion von Anfang an ausgeführt und muss demselben Ausführungspfad folgen wie die ursprüngliche Ausführung. Code außerhalb dauerhafter Operationen muss deterministisch sein und bei denselben Eingaben dieselben Ergebnisse liefern.

**Unterteilen Sie nichtdeterministische Operationen schrittweise:**
+ Generierung von Zufallszahlen und UUIDs
+ Aktuelle Uhrzeit oder Zeitstempel
+ Externe API-Aufrufe und Datenbankabfragen
+ Dateisystemoperationen

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';
import { randomUUID } from 'crypto';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Generate transaction ID inside a step
    const transactionId = await context.step('generate-transaction-id', async () => {
      return randomUUID();
    });
    
    // Use the same ID throughout execution, even during replay
    const payment = await context.step('process-payment', async () => {
      return processPayment(event.amount, transactionId);
    });
    
    return { statusCode: 200, transactionId, payment };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
import uuid

@durable_execution
def handler(event, context: DurableContext):
    # Generate transaction ID inside a step
    transaction_id = context.step(
        lambda _: str(uuid.uuid4()),
        name='generate-transaction-id'
    )
    
    # Use the same ID throughout execution, even during replay
    payment = context.step(
        lambda _: process_payment(event['amount'], transaction_id),
        name='process-payment'
    )
    
    return {'statusCode': 200, 'transactionId': transaction_id, 'payment': payment}
```

------

**Wichtig**  
Verwenden Sie keine globalen Variablen oder Schließungen, um den Status zwischen Schritten zu teilen. Übergeben Sie Daten durch Rückgabewerte. Der globale Status wird während der Wiedergabe unterbrochen, weil Schritte zwischengespeicherte Ergebnisse zurückgeben, globale Variablen jedoch zurückgesetzt werden.

**Vermeiden Sie Mutationen bei Verschlüssen:** Variablen, die in Closures erfasst wurden, können während der Wiedergabe Mutationen verlieren. Schritte geben zwischengespeicherte Ergebnisse zurück, aber Variablenaktualisierungen außerhalb des Schritts werden nicht wiederholt.

------
#### [ TypeScript ]

```
// ❌ WRONG: Mutations lost on replay
export const handler = withDurableExecution(async (event, context) => {
  let total = 0;
  
  for (const item of items) {
    await context.step(async () => {
      total += item.price; // ⚠️ Mutation lost on replay!
      return saveItem(item);
    });
  }
  
  return { total }; // Inconsistent value!
});

// ✅ CORRECT: Accumulate with return values
export const handler = withDurableExecution(async (event, context) => {
  let total = 0;
  
  for (const item of items) {
    total = await context.step(async () => {
      const newTotal = total + item.price;
      await saveItem(item);
      return newTotal; // Return updated value
    });
  }
  
  return { total }; // Consistent!
});

// ✅ EVEN BETTER: Use map for parallel processing
export const handler = withDurableExecution(async (event, context) => {
  const results = await context.map(
    items,
    async (ctx, item) => {
      await ctx.step(async () => saveItem(item));
      return item.price;
    }
  );
  
  const total = results.getResults().reduce((sum, price) => sum + price, 0);
  return { total };
});
```

------
#### [ Python ]

```
# ❌ WRONG: Mutations lost on replay
@durable_execution
def handler(event, context: DurableContext):
    total = 0
    
    for item in items:
        context.step(
            lambda _: save_item_and_mutate(item, total),  # ⚠️ Mutation lost on replay!
            name=f'save-item-{item["id"]}'
        )
    
    return {'total': total}  # Inconsistent value!

# ✅ CORRECT: Accumulate with return values
@durable_execution
def handler(event, context: DurableContext):
    total = 0
    
    for item in items:
        total = context.step(
            lambda _: save_item_and_return_total(item, total),
            name=f'save-item-{item["id"]}'
        )
    
    return {'total': total}  # Consistent!

# ✅ EVEN BETTER: Use map for parallel processing
@durable_execution
def handler(event, context: DurableContext):
    def process_item(ctx, item):
        ctx.step(lambda _: save_item(item))
        return item['price']
    
    results = context.map(items, process_item)
    total = sum(results.get_results())
    
    return {'total': total}
```

------

## Design für Idempotenz
<a name="durable-idempotency"></a>

Operationen können aufgrund von Wiederholungen oder Wiederholungen mehrfach ausgeführt werden. Operationen, die nicht idempotent sind, haben doppelte Nebenwirkungen, z. B. doppelte Gebühren für Kunden oder das Senden mehrerer E-Mails.

**Verwenden Sie Idempotenz-Token:** Generieren Sie Token innerhalb von Schritten und fügen Sie sie externen API-Aufrufen hinzu, um doppelte Operationen zu vermeiden.

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Generate idempotency token once
    const idempotencyToken = await context.step('generate-idempotency-token', async () => {
      return crypto.randomUUID();
    });
    
    // Use token to prevent duplicate charges
    const charge = await context.step('charge-payment', async () => {
      return paymentService.charge({
        amount: event.amount,
        cardToken: event.cardToken,
        idempotencyKey: idempotencyToken
      });
    });
    
    return { statusCode: 200, charge };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
import uuid

@durable_execution
def handler(event, context: DurableContext):
    # Generate idempotency token once
    idempotency_token = context.step(
        lambda _: str(uuid.uuid4()),
        name='generate-idempotency-token'
    )
    
    # Use token to prevent duplicate charges
    def charge_payment(_):
        return payment_service.charge(
            amount=event['amount'],
            card_token=event['cardToken'],
            idempotency_key=idempotency_token
        )
    
    charge = context.step(charge_payment, name='charge-payment')
    
    return {'statusCode': 200, 'charge': charge}
```

------

** at-most-onceSemantik verwenden:** Für kritische Operationen, die sich niemals duplizieren dürfen (Finanztransaktionen, Inventarabzüge), konfigurieren Sie den Ausführungsmodus. at-most-once

------
#### [ TypeScript ]

```
// Critical operation that must not duplicate
await context.step('deduct-inventory', async () => {
  return inventoryService.deduct(event.productId, event.quantity);
}, {
  executionMode: 'AT_MOST_ONCE_PER_RETRY'
});
```

------
#### [ Python ]

```
# Critical operation that must not duplicate
context.step(
    lambda _: inventory_service.deduct(event['productId'], event['quantity']),
    name='deduct-inventory',
    config=StepConfig(execution_mode='AT_MOST_ONCE_PER_RETRY')
)
```

------

**Datenbankidempotenz:** Verwenden Sie check-before-write Muster, bedingte Aktualisierungen oder Upsert-Operationen, um doppelte Datensätze zu verhindern.

## Verwalten Sie den Status effizient
<a name="durable-state-management"></a>

Jeder Checkpoint speichert den Status im persistenten Speicher. Große Zustandsobjekte erhöhen die Kosten, verlangsamen Checkpoints und beeinträchtigen die Leistung. Speichern Sie nur wichtige Daten zur Workflow-Koordination.

**Halten Sie den Status minimal:**
+ Speichern IDs und Verweise, nicht vollständige Objekte
+ Rufen Sie nach Bedarf detaillierte Daten in Schritten ab
+ Verwenden Sie Amazon S3 oder DynamoDB für große Datenmengen, übergeben Sie Referenzen im Status
+ Vermeiden Sie es, große Nutzlasten zwischen den Schritten weiterzugeben

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Store only the order ID, not the full order object
    const orderId = event.orderId;
    
    // Fetch data within each step as needed
    await context.step('validate-order', async () => {
      const order = await orderService.getOrder(orderId);
      return validateOrder(order);
    });
    
    await context.step('process-payment', async () => {
      const order = await orderService.getOrder(orderId);
      return processPayment(order);
    });
    
    return { statusCode: 200, orderId };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext

@durable_execution
def handler(event, context: DurableContext):
    # Store only the order ID, not the full order object
    order_id = event['orderId']
    
    # Fetch data within each step as needed
    context.step(
        lambda _: validate_order(order_service.get_order(order_id)),
        name='validate-order'
    )
    
    context.step(
        lambda _: process_payment(order_service.get_order(order_id)),
        name='process-payment'
    )
    
    return {'statusCode': 200, 'orderId': order_id}
```

------

## Entwerfen Sie effektive Schritte
<a name="durable-step-design"></a>

Stufen sind die grundlegende Arbeitseinheit für langlebige Funktionen. Gut durchdachte Schritte erleichtern das Verständnis, das Debuggen und die Wartung von Workflows.

**Prinzipien der schrittweisen Gestaltung:**
+ **Verwende aussagekräftige Namen** — Namen wie, `validate-order` anstatt Logs und Fehler leichter verständlich zu `step1` machen
+ **Namen statisch halten** — Verwenden Sie keine dynamischen Namen mit Zeitstempeln oder Zufallswerten. Schrittnamen müssen für die Wiedergabe deterministisch sein
+ **Ausgewogene Granularität** — Teilen Sie komplexe Vorgänge in gezielte Schritte auf, vermeiden Sie jedoch übermäßig kleine Schritte, die den Aufwand an den Checkpoints erhöhen
+ **Gruppenbezogene Operationen** — Operationen, die gemeinsam erfolgreich sein oder fehlschlagen sollten, gehören in denselben Schritt

## Verwenden Sie Warteoperationen effizient
<a name="durable-wait-operations"></a>

Wartevorgänge unterbrechen die Ausführung, ohne Ressourcen zu verbrauchen oder Kosten zu verursachen. Verwenden Sie sie, anstatt Lambda am Laufen zu halten.

**Zeitbasierte Wartezeiten:** Verwenden Sie diese Option `context.wait()` für Verzögerungen anstelle von oder. `setTimeout` `sleep`

**Externe Rückrufe:** `context.waitForCallback()` Wird verwendet, wenn auf externe Systeme gewartet wird. Stellen Sie immer Timeouts ein, um unbestimmte Wartezeiten zu vermeiden.

**Polling: Verwenden Sie diese Option** `context.waitForCondition()` mit exponentiellem Backoff, um externe Dienste abzufragen, ohne sie zu überfordern.

------
#### [ TypeScript ]

```
// Wait 24 hours without cost
await context.wait({ seconds: 86400 });

// Wait for external callback with timeout
const result = await context.waitForCallback(
  'external-job',
  async (callbackId) => {
    await externalService.submitJob({
      data: event.data,
      webhookUrl: `https://api.example.com/callbacks/${callbackId}`
    });
  },
  { timeout: { seconds: 3600 } }
);
```

------
#### [ Python ]

```
# Wait 24 hours without cost
context.wait(86400)

# Wait for external callback with timeout
result = context.wait_for_callback(
    lambda callback_id: external_service.submit_job(
        data=event['data'],
        webhook_url=f'https://api.example.com/callbacks/{callback_id}'
    ),
    name='external-job',
    config=WaitForCallbackConfig(timeout_seconds=3600)
)
```

------

## Weitere Überlegungen
<a name="durable-additional-considerations"></a>

**Fehlerbehandlung:** Versuchen Sie es erneut mit vorübergehenden Fehlern wie Netzwerk-Timeouts und Ratenbegrenzungen. Versuchen Sie es nicht erneut mit dauerhaften Fehlern wie ungültigen Eingabe- oder Authentifizierungsfehlern. Konfigurieren Sie Wiederholungsstrategien mit einer angemessenen maximalen Anzahl von Versuchen und Backoff-Raten. Ausführliche Beispiele finden Sie unter [Fehlerbehandlung](durable-execution-sdk-retries.md) und Wiederholungen.

**Leistung:** Minimiere die Größe von Checkpoints, indem du Referenzen statt vollständiger Payloads speicherst. Verwenden Sie `context.parallel()` und`context.map()`, um unabhängige Operationen gleichzeitig auszuführen. Batch-bezogene Operationen zur Reduzierung des Checkpoint-Overheads.

**Versionierung:** Rufen Sie Funktionen mit Versionsnummern oder Aliasnamen auf, um Ausführungen an bestimmte Codeversionen zu binden. Stellen Sie sicher, dass neue Codeversionen den Status älterer Versionen verarbeiten können. Benennen Sie Schritte nicht um und ändern Sie ihr Verhalten nicht so, dass die Wiedergabe unterbrochen wird.

**Serialisierung:** Verwenden Sie JSON-kompatible Typen für Operationseingaben und -ergebnisse. Konvertiert Datumsangaben in ISO-Zeichenketten und benutzerdefinierte Objekte in einfache Objekte, bevor Sie sie an dauerhafte Operationen übergeben.

**Überwachung:** Aktivieren Sie die strukturierte Protokollierung mit Ausführungs IDs - und Schrittnamen. Richten Sie CloudWatch Alarme für Fehlerraten und Ausführungsdauer ein. Verwenden Sie Tracing, um Engpässe zu identifizieren. Eine ausführliche Anleitung finden Sie unter [Überwachung](durable-monitoring.md) und Debuggen.

**Testen: Testen** Sie Happy Path, Fehlerbehandlung und Wiedergabeverhalten. Testen Sie Timeout-Szenarien für Rückrufe und Wartezeiten. Verwenden Sie lokale Tests, um die Iterationszeit zu reduzieren. Eine ausführliche Anleitung finden Sie unter [Dauerhafte Funktionen testen](durable-testing.md).

**Häufige Fehler, die Sie vermeiden sollten:** Verschachteln Sie `context.step()` Anrufe nicht, sondern verwenden Sie stattdessen untergeordnete Kontexte. Fassen Sie nicht deterministische Operationen schrittweise zusammen. Legen Sie immer Timeouts für Rückrufe fest. Gleichen Sie die Granularität der Schritte mit dem Checkpoint-Overhead ab. Speichern Sie Referenzen statt großer Objekte im Status.

## Weitere Ressourcen
<a name="durable-additional-resources"></a>
+ [Python SDK-Dokumentation](https://github.com/aws/aws-durable-execution-sdk-python/tree/main/docs) — Vollständige API-Referenz, Testmuster und erweiterte Beispiele
+ [TypeScript SDK-Dokumentation](https://github.com/aws/aws-durable-execution-sdk-js/tree/main/docs) — Vollständige API-Referenz, Testmuster und Beispiele für Fortgeschrittene