

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.

# Dauerhafte Lambda-Funktionen aufrufen
<a name="durable-invoking"></a>

Dauerhafte Lambda-Funktionen unterstützen dieselben Aufrufmethoden wie Standard-Lambda-Funktionen. Sie können langlebige Funktionen synchron, asynchron oder über Zuordnungen von Ereignisquellen aufrufen. Der Aufrufvorgang ist identisch mit Standardfunktionen, langlebige Funktionen bieten jedoch zusätzliche Funktionen für Ausführungen mit langer Laufzeit und automatische Statusverwaltung.

## Aufrufmethoden
<a name="durable-invoking-methods"></a>

**Synchroner Aufruf:** Rufen Sie eine dauerhafte Funktion auf und warten Sie auf die Antwort. Synchrone Aufrufe werden vom Lambda auf 15 Minuten (oder weniger, abhängig von der konfigurierten Funktion und dem Ausführungstimeout) begrenzt. Verwenden Sie synchrone Aufrufe, wenn Sie sofortige Ergebnisse benötigen oder wenn Sie Dienste integrieren, die eine Antwort erwarten. APIs Sie können Wait-Operationen für effiziente Berechnungen verwenden, ohne den Aufrufer zu unterbrechen — der Aufruf wartet, bis die gesamte Durable-Ausführung abgeschlossen ist. [Verwenden Sie für idempotente Ausführungsstarts den Parameter für den Ausführungsnamen, wie unter Idempotenz beschrieben.](durable-execution-idempotency.md)

```
aws lambda invoke \
  --function-name my-durable-function:1 \
  --cli-binary-format raw-in-base64-out \
  --payload '{"orderId": "12345"}' \
  response.json
```

**Asynchroner Aufruf:** Ein Ereignis zur Verarbeitung in eine Warteschlange stellen, ohne auf eine Antwort zu warten. Lambda stellt das Ereignis in eine Warteschlange und kehrt sofort zurück. Asynchrone Aufrufe unterstützen Ausführungsdauern von bis zu einem Jahr. Verwenden Sie den asynchronen Aufruf für fire-and-forget Szenarien oder wenn die Verarbeitung im Hintergrund erfolgen kann. [Verwenden Sie für idempotente Ausführungsstarts den Parameter für den Ausführungsnamen, wie unter Idempotenz beschrieben.](durable-execution-idempotency.md)

```
aws lambda invoke \
  --function-name my-durable-function:1 \
  --invocation-type Event \
  --cli-binary-format raw-in-base64-out \
  --payload '{"orderId": "12345"}' \
  response.json
```

**Zuordnungen von Ereignisquellen:** Konfigurieren Sie Lambda so, dass Ihre dauerhafte Funktion automatisch aufgerufen wird, wenn Datensätze von stream- oder warteschlangenbasierten Diensten wie Amazon SQS, Kinesis oder DynamoDB verfügbar sind. Zuordnungen von Ereignisquellen fragen die Ereignisquelle ab und rufen Ihre Funktion mit Datensatzstapeln auf. Einzelheiten zur Verwendung von Ereignisquellenzuordnungen mit dauerhaften Funktionen, einschließlich Beschränkungen für die Ausführungsdauer, finden Sie unter Zuordnungen von [Ereignisquellen](durable-invoking-esm.md) mit dauerhaften Funktionen.

[Vollständige Informationen zu den einzelnen Aufrufmethoden finden Sie unter [synchroner](invocation-sync.md) Aufruf und asynchroner Aufruf.](invocation-async.md)

**Anmerkung**  
Dauerhafte Funktionen unterstützen Dead-Letter-Warteschlangen (DLQs) für die Fehlerbehandlung, unterstützen jedoch keine Lambda-Ziele. Konfigurieren Sie eine DLQ, um Datensätze von fehlgeschlagenen Aufrufen zu erfassen.

## Qualifizierte Anforderung ARNs
<a name="durable-invoking-qualified-arns"></a>

Dauerhafte Funktionen benötigen qualifizierte Bezeichner für den Aufruf. Sie müssen dauerhafte Funktionen mit einer Versionsnummer, einem Alias oder aufrufen. `$LATEST` Sie können entweder einen vollqualifizierten ARN oder einen Funktionsnamen mit version/alias Suffix verwenden. Sie können keinen unqualifizierten Bezeichner (ohne Versions- oder Aliassuffix) verwenden.

**Gültige Aufrufe:**

```
# Using full ARN with version number
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1

# Using full ARN with alias
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:prod

# Using full ARN with $LATEST
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:$LATEST

# Using function name with version number
my-durable-function:1

# Using function name with alias
my-durable-function:prod
```

**Ungültige Aufrufe:**

```
# Unqualified ARN (not allowed)
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function

# Unqualified function name (not allowed)
my-durable-function
```

Diese Anforderung stellt sicher, dass langlebige Ausführungen während ihres gesamten Lebenszyklus konsistent bleiben. Wenn eine dauerhafte Ausführung gestartet wird, wird sie an die spezifische Funktionsversion gebunden. Wenn Ihre Funktion Stunden oder Tage später unterbrochen und wieder aufgenommen wird, ruft Lambda dieselbe Version auf, mit der die Ausführung gestartet wurde, wodurch die Codekonsistenz im gesamten Workflow gewährleistet wird.

**Bewährte Methode**  
Verwenden Sie nummerierte Versionen oder Aliase eher für langlebige Produktionsfunktionen als. `$LATEST` Nummerierte Versionen sind unveränderlich und unterstützen die deterministische Wiedergabe. Optional bieten Aliase eine stabile Referenz, die Sie aktualisieren können, um auf neue Versionen zu verweisen, ohne den Aufrufcode zu ändern. Wenn Sie einen Alias aktualisieren, verwenden neue Ausführungen die neue Version, während laufende Ausführungen mit ihrer ursprünglichen Version fortgesetzt werden. Sie können sie `$LATEST` für die Prototypenerstellung oder zur Verkürzung der Bereitstellungszeiten während der Entwicklung verwenden, da Sie wissen, dass Ausführungen möglicherweise nicht korrekt wiedergegeben werden (oder sogar fehlschlagen), wenn sich der zugrunde liegende Code während laufender Ausführungen ändert.

## Den Ausführungslebenszyklus verstehen
<a name="durable-invoking-execution-lifecycle"></a>

Wenn Sie eine dauerhafte Funktion aufrufen, erstellt Lambda eine dauerhafte Ausführung, die mehrere Funktionsaufrufe umfassen kann:

1. **Erster Aufruf:** Ihre Aufrufanforderung erstellt eine neue dauerhafte Ausführung. Lambda weist eine eindeutige Ausführungs-ID zu und beginnt mit der Verarbeitung.

1. **Ausführung und Checkpointing:** Während Ihre Funktion dauerhafte Operationen ausführt, erstellt das SDK Checkpoints, die den Fortschritt verfolgen.

1. **Aussetzung (falls erforderlich):** Wenn Ihre Funktion dauerhafte Wartezeiten wie `wait` oder oder oder `waitForCallback` automatische Schrittwiederholungen verwendet, unterbricht Lambda die Ausführung und beendet die Berechnung der Rechenzeit.

1. **Wiederaufnahme:** Wenn es Zeit ist, fortzufahren (auch nach erneuten Versuchen), ruft Lambda Ihre Funktion erneut auf. Das SDK spielt das Checkpoint-Protokoll erneut ab und setzt dort fort, wo die Ausführung unterbrochen wurde.

1. **Abschluss:** Wenn Ihre Funktion ein Endergebnis zurückgibt oder einen unbehandelten Fehler ausgibt, wird die dauerhafte Ausführung abgeschlossen.

Bei synchronen Aufrufen wartet der Aufrufer, bis die gesamte dauerhafte Ausführung abgeschlossen ist, einschließlich aller Warteoperationen. Wenn die Ausführung das Aufruf-Zeitlimit (15 Minuten oder weniger) überschreitet, wird das Timeout für den Aufruf überschritten. Bei asynchronen Aufrufen kehrt Lambda sofort zurück und die Ausführung wird unabhängig fortgesetzt. Verwenden Sie die dauerhafte Ausführung, um den Ausführungsstatus APIs zu verfolgen und die Endergebnisse abzurufen.

## Aus dem Anwendungscode aufrufen
<a name="durable-invoking-with-sdk"></a>

Verwenden Sie die AWS SDKs , um dauerhafte Funktionen aus Ihrem Anwendungscode aufzurufen. Der Aufrufvorgang ist identisch mit den Standardfunktionen:

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

```
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';

const client = new LambdaClient({});

// Synchronous invocation
const response = await client.send(new InvokeCommand({
  FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
  Payload: JSON.stringify({ orderId: '12345' })
}));

const result = JSON.parse(Buffer.from(response.Payload!).toString());

// Asynchronous invocation
await client.send(new InvokeCommand({
  FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
  InvocationType: 'Event',
  Payload: JSON.stringify({ orderId: '12345' })
}));
```

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

```
import boto3
import json

client = boto3.client('lambda')

# Synchronous invocation
response = client.invoke(
    FunctionName='arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
    Payload=json.dumps({'orderId': '12345'})
)

result = json.loads(response['Payload'].read())

# Asynchronous invocation
client.invoke(
    FunctionName='arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
    InvocationType='Event',
    Payload=json.dumps({'orderId': '12345'})
)
```

------

## Verkettete Aufrufe
<a name="durable-invoking-chained"></a>

Dauerhafte Funktionen können mithilfe der Operation von andere dauerhafte und nicht dauerhafte Funktionen aufrufen. `invoke` `DurableContext` Dadurch entsteht ein verketteter Aufruf, bei dem die aufrufende Funktion wartet (unterbricht), bis die aufgerufene Funktion abgeschlossen ist:

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

```
export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Invoke another durable function and wait for result
    const result = await context.invoke(
      'process-order',
      'arn:aws:lambda:us-east-1:123456789012:function:order-processor:1',
      { orderId: event.orderId }
    );
    
    return { statusCode: 200, body: JSON.stringify(result) };
  }
);
```

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

```
@durable_execution
def handler(event, context: DurableContext):
    # Invoke another durable function and wait for result
    result = context.invoke(
        'arn:aws:lambda:us-east-1:123456789012:function:order-processor:1',
        {'orderId': event['orderId']},
        name='process-order'
    )
    
    return {'statusCode': 200, 'body': json.dumps(result)}
```

------

Verkettete Aufrufe erzeugen einen Checkpoint in der aufrufenden Funktion. Wenn die aufrufende Funktion unterbrochen wird, wird sie vom Checkpoint aus mit dem Ergebnis der aufgerufenen Funktion fortgesetzt, ohne die Funktion erneut aufzurufen.

**Anmerkung**  
Kontenübergreifende, verkettete Aufrufe werden nicht unterstützt. Die aufgerufene Funktion muss sich in demselben AWS Konto wie die aufrufende Funktion befinden.

# Zuordnungen von Ereignisquellen mit dauerhaften Funktionen
<a name="durable-invoking-esm"></a>

Dauerhafte Funktionen funktionieren mit allen Lambda-Ereignisquellenzuordnungen. Konfigurieren Sie Ereignisquellenzuordnungen für dauerhafte Funktionen auf die gleiche Weise, wie Sie sie für Standardfunktionen konfigurieren. Ereignisquellenzuordnungen fragen automatisch Ereignisquellen wie Amazon SQS, Kinesis und DynamoDB Streams ab und rufen Ihre Funktion mit Datensatzstapeln auf.

Zuordnungen von Ereignisquellen sind nützlich für langlebige Funktionen, die Streams oder Warteschlangen mit komplexen, mehrstufigen Workflows verarbeiten. Sie können beispielsweise eine dauerhafte Funktion erstellen, die Amazon SQS SQS-Nachrichten mit Wiederholungen, externen API-Aufrufen und menschlichen Genehmigungen verarbeitet.

## Wie Zuordnungen von Ereignisquellen dauerhafte Funktionen aufrufen
<a name="durable-esm-invocation-behavior"></a>

Bei Zuordnungen von Ereignisquellen werden dauerhafte Funktionen synchron aufgerufen. Sie warten, bis die vollständige Ausführung abgeschlossen ist, bevor der nächste Stapel verarbeitet oder Datensätze als verarbeitet markiert werden. Wenn die gesamte Dauer der dauerhaften Ausführung 15 Minuten überschreitet, wird das Zeitlimit überschritten und die Ausführung schlägt fehl. Die Ereignisquellenzuordnung empfängt eine Timeout-Ausnahme und behandelt sie entsprechend ihrer Wiederholungskonfiguration.

## Ausführungslimit von 15 Minuten
<a name="durable-esm-duration-limit"></a>

Wenn dauerhafte Funktionen durch Zuordnungen von Ereignisquellen aufgerufen werden, darf die Gesamtdauer der dauerhaften Ausführung 15 Minuten nicht überschreiten. Diese Grenze gilt für die gesamte dauerhafte Ausführung von Anfang bis Ende, nicht nur für einzelne Funktionsaufrufen.

Dieses 15-Minuten-Limit ist unabhängig vom Lambda-Funktions-Timeout (ebenfalls maximal 15 Minuten). Das Funktions-Timeout steuert, wie lange jeder einzelne Aufruf ausgeführt werden kann, während das dauerhafte Ausführungs-Timeout die gesamte verstrichene Zeit vom Start bis zum Abschluss der Ausführung bestimmt.

**Beispielszenarien:**
+ **Gültig:** Eine dauerhafte Funktion verarbeitet eine Amazon SQS SQS-Nachricht in drei Schritten, die jeweils 2 Minuten dauern, und wartet dann 5 Minuten, bevor ein letzter Schritt abgeschlossen wird. Gesamtausführungszeit: 11 Minuten. Das funktioniert, weil die Gesamtsumme unter 15 Minuten liegt.
+ **Ungültig:** Eine dauerhafte Funktion verarbeitet eine Amazon SQS SQS-Nachricht, schließt die erste Verarbeitung in 2 Minuten ab und wartet dann 20 Minuten auf einen externen Rückruf, bevor der Vorgang abgeschlossen wird. Gesamtausführungszeit: 22 Minuten. Dies überschreitet das 15-Minuten-Limit und schlägt fehl.
+ **Ungültig:** Eine dauerhafte Funktion verarbeitet einen Kinesis-Datensatz mit mehreren Wartevorgängen, die zwischen den Schritten insgesamt 30 Minuten dauern. Obwohl jeder einzelne Aufruf schnell abgeschlossen wird, beträgt die Gesamtausführungszeit mehr als 15 Minuten.

**Wichtig**  
Konfigurieren Sie Ihr dauerhaftes Ausführungstimeout auf 15 Minuten oder weniger, wenn Sie Ereignisquellenzuordnungen verwenden. Andernfalls schlägt die Erstellung der Ereignisquellenzuordnung fehl. Wenn Ihr Workflow längere Ausführungszeiten erfordert, verwenden Sie das unten beschriebene Muster für Zwischenfunktionen.

## Zuordnungen von Ereignisquellen konfigurieren
<a name="durable-esm-configuration"></a>

Konfigurieren Sie Ereignisquellenzuordnungen für dauerhafte Funktionen mithilfe der Lambda-Konsole,, AWS CLI oder. AWS SDKs Alle Standardeigenschaften für die Zuordnung von Ereignisquellen gelten für dauerhafte Funktionen:

```
aws lambda create-event-source-mapping \
  --function-name arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1 \
  --event-source-arn arn:aws:sqs:us-east-1:123456789012:my-queue \
  --batch-size 10 \
  --maximum-batching-window-in-seconds 5
```

Denken Sie daran, bei der Konfiguration von Ereignisquellenzuordnungen für dauerhafte Funktionen einen qualifizierten ARN (mit Versionsnummer oder Alias) zu verwenden.

## Fehlerbehandlung bei Zuordnungen von Ereignisquellen
<a name="durable-esm-error-handling"></a>

Zuordnungen von Ereignisquellen bieten eine integrierte Fehlerbehandlung, die mit dauerhaften Funktionen funktioniert:
+ **Wiederholungsverhalten:** Wenn der erste Aufruf fehlschlägt, versucht die Zuordnung der Ereignisquelle entsprechend ihrer Wiederholungskonfiguration erneut. Konfigurieren Sie die maximale Anzahl an Wiederholungsversuchen und die Wiederholungsintervalle entsprechend Ihren Anforderungen.
+ **Warteschlangen für unzustellbare Briefe: Konfigurieren Sie eine Warteschlange** für unzustellbare Nachrichten, um Datensätze zu erfassen, die nach allen Wiederholungen fehlschlagen. Dies verhindert den Verlust von Nachrichten und ermöglicht die manuelle Überprüfung fehlgeschlagener Datensätze.
+ **Teilweise Batchfehler:** Verwenden Sie für Amazon SQS und Kinesis die Meldung teilweiser Batch-Fehler, um Datensätze einzeln zu verarbeiten und nur fehlgeschlagene Datensätze erneut zu versuchen.
+ Bei **Fehler halbieren:** Aktivieren Sie für Kinesis- und DynamoDB Streams die Option Halbieren bei Fehler, um fehlgeschlagene Batches aufzuteilen und problematische Datensätze zu isolieren.

**Anmerkung**  
Dauerhafte Funktionen unterstützen Dead-Letter-Queues (DLQs) für die Fehlerbehandlung, unterstützen aber keine Lambda-Ziele. Konfigurieren Sie eine DLQ, um Datensätze von fehlgeschlagenen Aufrufen zu erfassen.

Vollständige Informationen zur Fehlerbehandlung bei der Zuordnung von Ereignisquellen finden Sie unter Zuordnungen von [Ereignisquellen](invocation-eventsourcemapping.md).

## Verwendung einer Zwischenfunktion für Workflows mit langer Laufzeit
<a name="durable-esm-intermediary-function"></a>

Wenn Ihr Workflow mehr als 15 Minuten in Anspruch nimmt, verwenden Sie eine Standard-Lambda-Zwischenfunktion zwischen der Zuordnung der Ereignisquelle und Ihrer dauerhaften Funktion. Die Zwischenfunktion empfängt Ereignisse aus der Ereignisquellenzuordnung und ruft die dauerhafte Funktion asynchron auf, wodurch das Ausführungslimit von 15 Minuten aufgehoben wird.

Dieses Muster entkoppelt das synchrone Aufrufmodell der Ereignisquellenzuordnung vom Modell der dauerhaften Funktion mit langer Laufzeit. Bei der Zuordnung der Ereignisquellen wird die Zwischenfunktion aufgerufen, die nach dem Start der dauerhaften Ausführung schnell zurückkehrt. Die dauerhafte Funktion wird dann so lange wie nötig unabhängig ausgeführt (bis zu 1 Jahr).

### Architektur
<a name="durable-esm-intermediary-architecture"></a>

Das Muster der zwischengeschalteten Funktionen besteht aus drei Komponenten:

1. **Zuordnung der Ereignisquelle:** Ruft die Ereignisquelle ab (Amazon SQS, Kinesis, DynamoDB Streams) und ruft die Zwischenfunktion synchron mit Datensatzstapeln auf.

1. **Zwischenfunktion:** Eine Standard-Lambda-Funktion, die Ereignisse aus der Ereignisquellenzuordnung empfängt, die Daten bei Bedarf validiert und transformiert und die dauerhafte Funktion asynchron aufruft. Diese Funktion wird schnell abgeschlossen (normalerweise in weniger als 1 Sekunde) und gibt die Steuerung an die Ereignisquellenzuordnung zurück.

1. **Dauerhafte Funktion:** Verarbeitet das Ereignis mit einer komplexen, mehrstufigen Logik, die über längere Zeiträume ausgeführt werden kann. Wird asynchron aufgerufen, sodass es nicht durch das 15-Minuten-Limit eingeschränkt ist.

### Implementierung
<a name="durable-esm-intermediary-implementation"></a>

Die Zwischenfunktion empfängt das gesamte Ereignis aus der Ereignisquellenzuordnung und ruft die dauerhafte Funktion asynchron auf. Verwenden Sie den Parameter für den Ausführungsnamen, um sicherzustellen, dass die idempotente Ausführung gestartet wird, und verhindern Sie so eine doppelte Verarbeitung, falls die Ereignisquellenzuordnung erneut versucht:

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

```
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';
import { SQSEvent } from 'aws-lambda';
import { createHash } from 'crypto';

const lambda = new LambdaClient({});

export const handler = async (event: SQSEvent) => {
  // Invoke durable function asynchronously with execution name
  await lambda.send(new InvokeCommand({
    FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
    InvocationType: 'Event',
    Payload: JSON.stringify({
      executionName: event.Name,
      event: event
    })
  }));
  
  return { statusCode: 200 };
};
```

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

```
import boto3
import json
import hashlib

lambda_client = boto3.client('lambda')

def handler(event, context):  
    # Invoke durable function asynchronously with execution name
    lambda_client.invoke(
        FunctionName='arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
        InvocationType='Event',
        Payload=json.dumps({
            'executionName': execution_name,
            'event': event["name"]
        })
    )
    
    return {'statusCode': 200}
```

------

Verwenden Sie [Powertools für](https://docs.aws.amazon.com//powertools/) Idempotenz in der Zwischenfunktion selbst, um doppelte Aufrufe der dauerhaften Funktion AWS Lambda zu verhindern, falls die Zuordnung der Ereignisquelle die Zwischenfunktion erneut versucht.

Die dauerhafte Funktion empfängt die Nutzdaten mit dem Namen der Ausführung und verarbeitet alle Datensätze mit lang andauernder Logik:

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

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

export const handler = withDurableExecution(
  async (payload: any, context: DurableContext) => {
    const sqsEvent = payload.event;
    
    // Process each record with complex, multi-step logic
    const results = await context.map(
      sqsEvent.Records,
      async (ctx, record) => {
        const validated = await ctx.step('validate', async () => {
          return validateOrder(JSON.parse(record.body));
        });
        
        // Wait for external approval (could take hours or days)
        const approval = await ctx.waitForCallback(
          'approval',
          async (callbackId) => {
            await requestApproval(callbackId, validated);
          },
          { timeout: { hours: 48 } }
        );
        
        // Complete processing
        return await ctx.step('complete', async () => {
          return completeOrder(validated, approval);
        });
      }
    );
    
    return { statusCode: 200, processed: results.getResults().length };
  }
);
```

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

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
from aws_durable_execution_sdk_python.config import Duration, WaitForCallbackConfig
from collections.abc import Sequence
import json

def validate_order(order_data: dict) -> dict:
    """Validate order data - always passes."""
    return order_data

def request_approval(callback_id: str, validated_order: dict) -> None:
    """Request approval for the order - always passes."""
    pass

def complete_order(validated_order: dict, approval_result: str) -> dict:
    """Complete the order processing - always passes."""
    return validated_order

@durable_execution
def lambda_handler(payload, context: DurableContext):
    sqs_event = payload['event']

    def process_record(
        ctx: DurableContext, 
        record: dict, 
        index: int, 
        items: Sequence[dict]
    ) -> dict:
        validated = ctx.step(
            lambda _: validate_order(json.loads(record['body'])),
            name=f'validate-{index}'
        )

        approval = ctx.wait_for_callback(
            submitter=lambda callback_id, wait_ctx: request_approval(callback_id, validated),
            name=f'approval-{index}',
            config=WaitForCallbackConfig(timeout=Duration.from_seconds(172800))
        )

        return ctx.step(
            lambda _: complete_order(validated, approval),
            name=f'complete-{index}'
        )

    results = context.map(
        inputs=sqs_event['Records'],
        func=process_record,
        name='process-records'
    )

    return {
        'statusCode': 200, 
        'started': results.started_count,
        'completed': results.success_count,
        'failed': results.failure_count,
        'total': results.total_count
    }
```

------

### Wesentliche Überlegungen
<a name="durable-esm-intermediary-tradeoffs"></a>

Mit diesem Muster wird das Ausführungslimit von 15 Minuten aufgehoben, indem die Zuordnung der Ereignisquelle von der dauerhaften Ausführung entkoppelt wird. Die Zwischenfunktion kehrt unmittelbar nach dem Start der dauerhaften Ausführung zurück, sodass die Verarbeitung der Ereignisquellenzuordnung fortgesetzt werden kann. Die dauerhafte Funktion wird dann so lange wie nötig unabhängig ausgeführt.

Die Zwischenfunktion ist erfolgreich, wenn sie die dauerhafte Funktion aufruft, nicht wenn die dauerhafte Ausführung abgeschlossen ist. Wenn die dauerhafte Ausführung später fehlschlägt, versucht die Zuordnung der Ereignisquelle nicht erneut, da der Stapel bereits erfolgreich verarbeitet wurde. Implementieren Sie die Fehlerbehandlung in der dauerhaften Funktion und konfigurieren Sie Warteschlangen für fehlerhafte Ausführungen.

Verwenden Sie den Parameter für den Ausführungsnamen, um sicherzustellen, dass die idempotente Ausführung gestartet wird. Wenn die Zuordnung der Ereignisquelle erneut versucht, die Zwischenfunktion zu verwenden, startet die dauerhafte Funktion keine doppelte Ausführung, da der Ausführungsname bereits vorhanden ist.

## Unterstützte Ereignisquellen
<a name="durable-esm-supported-sources"></a>

Dauerhafte Funktionen unterstützen alle Lambda-Ereignisquellen, die Ereignisquellenzuordnungen verwenden:
+ Amazon SQS SQS-Warteschlangen (Standard und FIFO)
+ Kinesis-Streams
+ DynamoDB Streams
+ Amazon Managed Streaming for Apache Kafka (Amazon MSK)
+ Selbstverwaltetes Apache Kafka
+ Amazon MQ (ActiveMQ und RabbitMQ)
+ Amazon DocumentDB DocumentDB-Change-Streams

Für alle Arten von Ereignisquellen gilt beim Aufrufen dauerhafter Funktionen eine maximale Ausführungsdauer von 15 Minuten.

# Wiederholungen für langlebige Lambda-Funktionen
<a name="durable-execution-sdk-retries"></a>

Langlebige Funktionen bieten automatische Wiederholungsfunktionen, die Ihre Anwendungen widerstandsfähig gegen vorübergehende Ausfälle machen. Das SDK verarbeitet Wiederholungen auf zwei Ebenen: schrittweise Wiederholungen bei Ausfällen der Geschäftslogik und Backend-Wiederholungen bei Infrastrukturausfällen.

## Schrittweise Wiederholungen
<a name="durable-step-retries"></a>

Wenn innerhalb eines Schritts eine nicht abgefangene Ausnahme auftritt, wiederholt das SDK den Schritt automatisch auf der Grundlage der konfigurierten Wiederholungsstrategie. Wiederholungen von Schritten sind Operationen, bei denen das SDK die Ausführung unterbrechen und später fortsetzen kann, ohne dass der Fortschritt verloren geht.

### Verhalten bei schrittweisen Wiederholungen
<a name="durable-step-retry-behavior"></a>

In der folgenden Tabelle wird beschrieben, wie das SDK Ausnahmen in Schritten behandelt:


| Szenario | Was passiert | Messung der Auswirkungen | 
| --- | --- | --- | 
| Ausnahme im Gleichschritt mit den verbleibenden Wiederholungsversuchen | Das SDK erstellt einen Checkpoint für den erneuten Versuch und unterbricht die Funktion. Beim nächsten Aufruf wiederholt sich der Schritt mit der konfigurierten Backoff-Verzögerung. | 1 Vorgang \$1 Fehler, Payload-Größe | 
| Ausnahme im Schritt ohne verbleibende Wiederholungsversuche | Der Schritt schlägt fehl und löst eine Ausnahme aus. Wenn Ihr Handler-Code diese Ausnahme nicht catch, schlägt die gesamte Ausführung fehl. | 1 Vorgang \$1 Fehler, Größe der Nutzlast | 

Wenn ein Schritt erneut versucht werden muss, überprüft das SDK den Wiederholungsstatus und beendet den Lambda-Aufruf, wenn keine andere Arbeit ausgeführt wird. Auf diese Weise kann das SDK Backoff-Verzögerungen implementieren, ohne Rechenressourcen zu verbrauchen. Die Funktion wird nach Ablauf der Backoff-Periode automatisch wieder aufgenommen.

### Konfiguration von Strategien zur schrittweisen Wiederholung
<a name="durable-step-retry-configuration"></a>

Konfigurieren Sie Wiederholungsstrategien, um zu steuern, wie Schritte mit Fehlern umgehen. Sie können maximale Versuche, Backoff-Intervalle und Bedingungen für Wiederholungsversuche angeben.

**Exponentieller Backoff mit maximaler Anzahl von Versuchen:**

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

```
const result = await context.step('call-api', async () => {
  const response = await fetch('https://api.example.com/data');
  if (!response.ok) throw new Error(`API error: ${response.status}`);
  return await response.json();
}, {
  retryStrategy: (error, attemptCount) => {
    if (attemptCount >= 5) {
      return { shouldRetry: false };
    }
    // Exponential backoff: 2s, 4s, 8s, 16s, 32s (capped at 300s)
    const delay = Math.min(2 * Math.pow(2, attemptCount - 1), 300);
    return { shouldRetry: true, delay: { seconds: delay } };
  }
});
```

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

```
def retry_strategy(error, attempt_count):
    if attempt_count >= 5:
        return {'should_retry': False}
    # Exponential backoff: 2s, 4s, 8s, 16s, 32s (capped at 300s)
    delay = min(2 * (2 ** (attempt_count - 1)), 300)
    return {'should_retry': True, 'delay': delay}

result = context.step(
    lambda _: call_external_api(),
    name='call-api',
    config=StepConfig(retry_strategy=retry_strategy)
)
```

------

**Backoff mit festem Intervall:**

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

```
const orders = await context.step('query-orders', async () => {
  return await queryDatabase(event.userId);
}, {
  retryStrategy: (error, attemptCount) => {
    if (attemptCount >= 3) {
      return { shouldRetry: false };
    }
    return { shouldRetry: true, delay: { seconds: 5 } };
  }
});
```

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

```
def retry_strategy(error, attempt_count):
    if attempt_count >= 3:
        return {'should_retry': False}
    return {'should_retry': True, 'delay': 5}

orders = context.step(
    lambda _: query_database(event['userId']),
    name='query-orders',
    config=StepConfig(retry_strategy=retry_strategy)
)
```

------

**Bedingter Wiederholungsversuch (nur bei bestimmten Fehlern wiederholen):**

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

```
const result = await context.step('call-rate-limited-api', async () => {
  const response = await fetch('https://api.example.com/data');
  
  if (response.status === 429) throw new Error('RATE_LIMIT');
  if (response.status === 504) throw new Error('TIMEOUT');
  if (!response.ok) throw new Error(`API_ERROR_${response.status}`);
  
  return await response.json();
}, {
  retryStrategy: (error, attemptCount) => {
    // Only retry rate limits and timeouts
    const isRetryable = error.message === 'RATE_LIMIT' || error.message === 'TIMEOUT';
    
    if (!isRetryable || attemptCount >= 3) {
      return { shouldRetry: false };
    }
    
    // Exponential backoff: 1s, 2s, 4s (capped at 30s)
    const delay = Math.min(Math.pow(2, attemptCount - 1), 30);
    return { shouldRetry: true, delay: { seconds: delay } };
  }
});
```

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

```
def retry_strategy(error, attempt_count):
    # Only retry rate limits and timeouts
    is_retryable = str(error) in ['RATE_LIMIT', 'TIMEOUT']
    
    if not is_retryable or attempt_count >= 3:
        return {'should_retry': False}
    
    # Exponential backoff: 1s, 2s, 4s (capped at 30s)
    delay = min(2 ** (attempt_count - 1), 30)
    return {'should_retry': True, 'delay': delay}

result = context.step(
    lambda _: call_rate_limited_api(),
    name='call-rate-limited-api',
    config=StepConfig(retry_strategy=retry_strategy)
)
```

------

**Wiederholungen deaktivieren:**

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

```
const isDuplicate = await context.step('check-duplicate', async () => {
  return await checkIfOrderExists(event.orderId);
}, {
  retryStrategy: () => ({ shouldRetry: false })
});
```

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

```
is_duplicate = context.step(
    lambda _: check_if_order_exists(event['orderId']),
    name='check-duplicate',
    config=StepConfig(
        retry_strategy=lambda error, attempt: {'should_retry': False}
    )
)
```

------

Wenn die Wiederholungsstrategie zurückkehrt`shouldRetry: false`, schlägt der Schritt ohne erneute Versuche sofort fehl. Verwenden Sie diese Option für Operationen, die nicht wiederholt werden sollten, z. B. Idempotenzprüfungen oder Operationen mit Nebenwirkungen, die nicht sicher wiederholt werden können.

## Ausnahmen außerhalb von Schritten
<a name="durable-handler-exceptions"></a>

Wenn in Ihrem Handlercode, aber außerhalb eines Schritts eine nicht abgefangene Ausnahme auftritt, markiert das SDK die Ausführung als fehlgeschlagen. Dadurch wird sichergestellt, dass Fehler in Ihrer Anwendungslogik ordnungsgemäß erfasst und gemeldet werden.


| Szenario | Was passiert | Messung der Auswirkungen | 
| --- | --- | --- | 
| Ausnahme im Handler-Code außerhalb eines beliebigen Schritts | Das SDK markiert die Ausführung als FEHLGESCHLAGEN und gibt den Fehler zurück. Die Ausnahme wird nicht automatisch wiederholt. | Fehler bei der Größe der Payload | 

Um die automatische Wiederholung von fehleranfälligem Code zu aktivieren, schließen Sie den Vorgang in einem Schritt mit einer Wiederholungsstrategie ab. Schritte bieten automatische Wiederholungsversuche mit konfigurierbarem Backoff, während Code außerhalb von Schritten sofort fehlschlägt.

## Wiederholungen im Backend
<a name="durable-backend-retries"></a>

Backend-Wiederholungen treten auf, wenn Lambda auf Infrastrukturausfälle oder Laufzeitfehler stößt oder wenn das SDK nicht mit dem Durable Execution Service kommunizieren kann. Lambda versucht diese Fehler automatisch erneut, damit Ihre dauerhaften Funktionen nach vorübergehenden Infrastrukturproblemen wieder hergestellt werden können.

### Szenarien für Wiederholungsversuche im Backend
<a name="durable-backend-retry-scenarios"></a>

Lambda versucht automatisch, Ihre Funktion erneut auszuführen, wenn sie auf die folgenden Szenarien trifft:
+ **Interne Dienstfehler** — Wenn Lambda oder der Durable Execution Service einen 5xx-Fehler zurückgibt, was auf ein vorübergehendes Serviceproblem hinweist.
+ **Drosselung** — Wenn Ihre Funktion aufgrund von Parallelitätsbeschränkungen oder Servicekontingenten gedrosselt wird.
+ **Timeouts** — Wenn das SDK den Durable Execution Service innerhalb des Timeout-Zeitraums nicht erreichen kann.
+ **Sandbox-Initialisierungsfehler** — Wenn Lambda die Ausführungsumgebung nicht initialisieren kann.
+ **Laufzeitfehler** — Wenn die Lambda-Laufzeit auf Fehler außerhalb Ihres Funktionscodes stößt, z. B. out-of-memory Fehler oder Prozessabstürze.
+ **Ungültige Checkpoint-Token-Fehler** — Wenn das Checkpoint-Token nicht mehr gültig ist, typischerweise aufgrund von Statusänderungen auf der Serviceseite.

In der folgenden Tabelle wird beschrieben, wie das SDK mit diesen Szenarien umgeht:


| Szenario | Was passiert | Messung der Auswirkungen | 
| --- | --- | --- | 
| Laufzeitfehler außerhalb des Durable-Handlers (OOM, Timeout, Absturz) | Lambda versucht den Aufruf automatisch erneut. Das SDK wiederholt die Wiedergabe ab dem letzten Checkpoint, wobei abgeschlossene Schritte übersprungen werden. | Fehler: Payload-Größe \$1 1 Vorgang pro Wiederholung | 
| Dienstfehler (5xx) oder Timeout beim Aufrufen/CheckpointDurableExecutionGetDurableExecutionState APIs | Lambda versucht den Aufruf automatisch erneut. Das SDK wiederholt die Wiedergabe ab dem letzten Checkpoint. | Fehler: Payload-Größe \$1 1 Vorgang pro Wiederholungsversuch | 
| Drosselung (429) oder ungültiges Checkpoint-Token beim Aufrufen von/CheckpointDurableExecutionGetDurableExecutionState APIs | Lambda wiederholt den Aufruf automatisch mit exponentiellem Backoff. Das SDK wiederholt die Wiedergabe ab dem letzten Checkpoint. | Fehler: Payload-Größe \$1 1 Vorgang pro Wiederholungsversuch | 
| Client-Fehler (4xx, außer 429 und ungültigem Token) wenn/CheckpointDurableExecutionGetDurableExecutionState APIs | Das SDK markiert die Ausführung als FEHLGESCHLAGEN. Es erfolgt kein automatischer Wiederholungsversuch, da der Fehler auf ein permanentes Problem hinweist. | Fehler bei der Größe der Payload | 

Backend-Wiederholungen verwenden exponentielles Backoff und werden fortgesetzt, bis die Funktion erfolgreich ist oder das Ausführungstimeout erreicht ist. Während der Wiedergabe überspringt das SDK abgeschlossene Prüfpunkte und setzt die Ausführung ab dem letzten erfolgreichen Vorgang fort, um sicherzustellen, dass Ihre Funktion abgeschlossene Arbeit nicht erneut ausführt.

## Versuchen Sie es erneut mit bewährten Methoden
<a name="durable-retry-best-practices"></a>

Beachten Sie bei der Konfiguration von Wiederholungsstrategien die folgenden bewährten Methoden:
+ **Konfigurieren Sie explizite Wiederholungsstrategien** — Verlassen Sie sich nicht auf das standardmäßige Wiederholungsverhalten in der Produktion. Konfigurieren Sie Strategien für explizite Wiederholungen mit einer für Ihren Anwendungsfall angemessenen maximalen Anzahl von Versuchen und Backoff-Intervallen.
+ **Verwenden Sie bedingte Wiederholungen** — Implementieren Sie `shouldRetry` Logik, um nur vorübergehende Fehler (Ratenbegrenzungen, Timeouts) zu wiederholen und bei dauerhaften Fehlern (Validierungsfehler, nicht gefunden) schnell fehlzuschlagen.
+ **Stellen Sie eine angemessene maximale Anzahl von Versuchen** ein — Balance zwischen Belastbarkeit und Ausführungszeit. Zu viele Wiederholungen können die Fehlererkennung verzögern, während zu wenige Versuche zu unnötigen Fehlern führen können.
+ **Exponentielles Backoff verwenden — Exponentielles Backoff** reduziert die Belastung nachgeschalteter Dienste und erhöht die Wahrscheinlichkeit einer Wiederherstellung nach vorübergehenden Ausfällen.
+ **Fehleranfälligen Code schrittweise zusammenfassen — Code außerhalb von Schritten kann nicht automatisch** wiederholt werden. Integrieren Sie externe API-Aufrufe, Datenbankabfragen und andere fehleranfällige Operationen schrittweise mit Wiederholungsstrategien.
+ **Überwachen Sie Wiederholungsmetriken** — Verfolgen Sie schrittweise Wiederholungsvorgänge und Ausführungsfehler in Amazon CloudWatch , um Muster zu identifizieren und Wiederholungsstrategien zu optimieren.

# Idempotenz
<a name="durable-execution-idempotency"></a>

Dauerhafte Funktionen bieten eine eingebaute Idempotenz für Ausführungsstarts anhand von Ausführungsnamen. Wenn Sie einen Ausführungsnamen angeben, verwendet Lambda ihn, um doppelte Ausführungen zu verhindern und sichere Wiederholungen von Aufrufanforderungen zu ermöglichen. Schritte haben standardmäßig eine at-least-once Ausführungssemantik — während der Wiedergabe gibt das SDK Checkpoint-Ergebnisse zurück, ohne abgeschlossene Schritte erneut auszuführen, aber Ihre Geschäftslogik muss idempotent sein, um mögliche Wiederholungen vor Abschluss zu verarbeiten.

**Anmerkung**  
Lambda Event Source Mappings (ESM) unterstützen Idempotenz beim Start nicht. Daher startet jeder Aufruf (einschließlich Wiederholungen) eine neue dauerhafte Ausführung. Um eine idempotente Ausführung mit Ereignisquellenzuordnungen sicherzustellen, implementieren Sie entweder Idempotenzlogik in Ihrem Funktionscode, z. B. mit [Powertools for](https://docs.aws.amazon.com//powertools/), AWS Lambda oder verwenden Sie eine reguläre Lambda-Funktion als Proxy (Dispatcher), um eine dauerhafte Funktion mit einem Idempotenzschlüssel (Ausführungsnamenparameter) aufzurufen.

## Namen der Ausführung
<a name="durable-idempotency-execution-names"></a>

Sie können einen Ausführungsnamen angeben, wenn Sie eine dauerhafte Funktion aufrufen. Der Ausführungsname fungiert als Idempotenzschlüssel, sodass Sie Aufrufanforderungen sicher wiederholen können, ohne dass doppelte Ausführungen erforderlich sind. Wenn Sie keinen Namen angeben, generiert Lambda automatisch eine eindeutige Ausführungs-ID.

Ausführungsnamen müssen innerhalb Ihres Kontos und Ihrer Region eindeutig sein. Wenn Sie eine Funktion mit einem bereits vorhandenen Ausführungsnamen aufrufen, hängt das Verhalten von Lambda vom Status der vorhandenen Ausführung ab und davon, ob die Nutzlast übereinstimmt.

## Verhalten bei Idempotenz
<a name="durable-idempotency-behavior"></a>

In der folgenden Tabelle wird beschrieben, wie Lambda Aufrufanforderungen verarbeitet, je nachdem, ob Sie einen Ausführungsnamen angeben, welchen Ausführungsstatus es gibt und ob die Nutzlast übereinstimmt:


| Szenario | Name angegeben? | Bestehender Ausführungsstatus | Nutzlast identisch? | Behavior | 
| --- | --- | --- | --- | --- | 
| 1 | Nein | – | – | Neue Ausführung gestartet: Lambda generiert eine eindeutige Ausführungs-ID und startet eine neue Ausführung | 
| 2 | Ja | Hat nie existiert oder die Aufbewahrung ist abgelaufen | – | Neue Ausführung gestartet: Lambda startet eine neue Ausführung mit dem angegebenen Namen | 
| 3 | Ja | In Ausführung | Ja | Idempotenter Start: Lambda gibt die vorhandenen Ausführungsinformationen zurück, ohne ein Duplikat zu starten. Bei synchronen Aufrufen dient dies als erneutes Anhängen an die laufende Ausführung | 
| 4 | Ja | In Ausführung | Nein | Fehler: Lambda gibt einen DurableExecutionAlreadyExists Fehler zurück, weil eine Ausführung mit diesem Namen bereits mit einer anderen Nutzlast ausgeführt wird | 
| 5 | Ja | Geschlossen (erfolgreich, fehlgeschlagen, gestoppt oder Zeitlimit überschritten) | Ja | Idempotenter Start: Lambda gibt die vorhandenen Ausführungsinformationen zurück, ohne eine neue Ausführung zu starten. Das Ergebnis der geschlossenen Ausführung wird zurückgegeben | 
| 6 | Ja | Geschlossen (erfolgreich, fehlgeschlagen, gestoppt oder Zeitlimit überschritten) | Nein | Fehler: Lambda gibt einen DurableExecutionAlreadyExists Fehler zurück, weil eine Ausführung mit diesem Namen bereits mit einer anderen Nutzlast abgeschlossen wurde | 

**Hinweis**  
Die Szenarien 3 und 5 zeigen ein idempotentes Verhalten, bei dem Lambda doppelte Aufrufanforderungen sicher verarbeitet, indem es vorhandene Ausführungsinformationen zurückgibt, anstatt Duplikate zu erstellen.

## Schritt Idempotenz
<a name="durable-idempotency-steps"></a>

Schritte haben standardmäßig eine at-least-once Ausführungssemantik. Wenn Ihre Funktion nach einem Warten, einem Rückruf oder einem Fehler erneut ausgeführt wird, überprüft das SDK jeden Schritt anhand des Checkpoint-Logs. Für Schritte, die bereits abgeschlossen wurden, gibt das SDK das Checkpoint-Ergebnis zurück, ohne die Schrittlogik erneut auszuführen. Wenn ein Schritt jedoch fehlschlägt oder die Funktion unterbrochen wird, bevor der Schritt abgeschlossen ist, kann der Schritt mehrmals ausgeführt werden.

Ihre in Schritten unterteilte Geschäftslogik muss idempotent sein, um potenzielle Wiederholungsversuche zu bewältigen. Verwenden Sie Idempotenzschlüssel, um sicherzustellen, dass Operationen wie Zahlungen oder Datenbankschreibvorgänge nur einmal ausgeführt werden, auch wenn der Schritt erneut versucht wird.

**Beispiel: Schrittweise Verwendung von Idempotenzschlüsseln**

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

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

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

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

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
import uuid

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

------

Sie können Schritte so konfigurieren, dass sie die at-most-once Ausführungssemantik verwenden, indem Sie den Ausführungsmodus auf setzen. `AT_MOST_ONCE_PER_RETRY` Dadurch wird sichergestellt, dass der Schritt pro Wiederholungsversuch höchstens einmal ausgeführt wird, aber möglicherweise überhaupt nicht ausgeführt wird, wenn die Funktion unterbrochen wird, bevor der Schritt abgeschlossen ist.

Das SDK erzwingt eine deterministische Wiedergabe, indem es während der Wiedergabe überprüft, ob die Namen und die Reihenfolge der Schritte mit dem Checkpoint-Protokoll übereinstimmen. Wenn Ihr Code versucht, Schritte in einer anderen Reihenfolge oder mit anderen Namen auszuführen, gibt das SDK eine aus. `NonDeterministicExecutionError`

**So funktioniert die Wiedergabe mit abgeschlossenen Schritten:**

1. Erster Aufruf: Die Funktion führt Schritt A aus, erstellt einen Checkpoint und wartet dann

1. Zweiter Aufruf (nach dem Warten): Die Funktion wird von Anfang an wiederholt, Schritt A gibt sofort ein Checkpoint-Ergebnis zurück, ohne es erneut auszuführen, und fährt dann mit Schritt B fort

1. Dritter Aufruf (nach erneuter Wartezeit): Die Funktion wird von Anfang an wiederholt, die Schritte A und B geben sofort Checkpoint-Ergebnisse zurück und fährt dann mit Schritt C fort

Dieser Wiederholungsmechanismus stellt sicher, dass abgeschlossene Schritte nicht erneut ausgeführt werden, aber Ihre Geschäftslogik muss immer noch idempotent sein, um Wiederholungen vor Abschluss zu verarbeiten.