

# 基本概念
<a name="durable-basic-concepts"></a>

Lambda 为 JavaScript、TypeScript 和 Python 提供持久性执行 SDK。这些 SDK 是构建持久性函数的基础，提供了记录进度检查点、处理重试和管理执行流所需的基元。有关完整的 SDK 文档和示例，请参阅 GitHub 上的 [JavaScript/TypeScript SDK](https://github.com/aws/aws-durable-execution-sdk-js) 和 [Python SDK](https://github.com/aws/aws-durable-execution-sdk-python)。

## 持久执行
<a name="durable-execution-concept"></a>

**持久执行**代表了 Lambda 持久性函数的整个生命周期，它通过检查点和回放机制来跟踪业务逻辑的执行进度、暂停执行以及从故障中恢复。当函数在暂停或中断后恢复时，会回放之前完成的检查点，然后函数继续执行。

该生命周期可能包括多次调用 Lambda 函数以完成执行，尤其是在暂停或故障恢复之后。这种方法使您的函数能够长时间运行（最长一年），同时即使出现中断，也能保持可靠的进度。

**重播的工作原理**  
Lambda 会持续记录所有持久操作（步骤、等待以及其他操作）的执行过程，直至您的函数完成执行。当您的函数需要暂停或遇到中断时，Lambda 会保存此检查点日志并停止执行。当需要恢复时，Lambda 会从头开始再次调用您的函数并重播检查点日志，从而用存储的值替代已完成的操作。这意味着您的代码会再次运行，但之前已完成的步骤不会再次执行。而是会使用它们存储的结果。

这种重播机制是理解持久性函数的基础。您的代码在重播期间必须是确定性的，也就是说，对于相同的输入，它会产生相同的输出结果。避免在步骤之外进行会产生副作用的操作（例如生成随机数或获取当前时间），因为这些操作在重播时可能会产生不同的结果，从而导致非确定性行为。

## DurableContext
<a name="durable-context-concept"></a>

**DurableContext** 是您的持久性函数接收的上下文对象。它提供了持久操作的方法，例如创建检查点和管理执行流的步骤和等待。

您的持久性函数会接收 `DurableContext` 而不是默认的 Lambda 上下文：

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

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

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const result = await context.step(async () => {
      return "step completed";
    });
    return result;
  },
);
```

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

```
from aws_durable_execution_sdk_python import (
    DurableContext,
    durable_execution,
    durable_step,
)

@durable_step
def my_step(step_context, data):
    # Your business logic
    return result

@durable_execution
def handler(event, context: DurableContext):
    result = context.step(my_step(event["data"]))
    return result
```

------

用于持久性函数的 Python SDK 会使用同步方法，但不支持 `await`。TypeScript SDK 使用 `async/await`。

## Steps
<a name="steps-concept"></a>

**步骤**通过内置重试和自动检查点机制运行业务逻辑。每个步骤都会保存其结果，这样即使出现中断情况，您的函数也能从任何已完成的步骤处恢复执行。

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

```
// Each step is automatically checkpointed
const order = await context.step(async () => processOrder(event));
const payment = await context.step(async () => processPayment(order));
const result = await context.step(async () => completeOrder(payment));
```

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

```
# Each step is automatically checkpointed
order = context.step(lambda: process_order(event))
payment = context.step(lambda: process_payment(order))
result = context.step(lambda: complete_order(payment))
```

------

## 等待状态
<a name="wait-states-concept"></a>

**等待状态**是计划中的暂停，在该状态下，您的函数停止运行（并停止收费），直到需要继续运行时。使用它们来等待时间段、外部回调或特定条件。

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

```
// Wait for 1 hour without consuming resources
await context.wait({ seconds:3600 });

// Wait for external callback
const approval = await context.waitForCallback(
  async (callbackId) => sendApprovalRequest(callbackId)
);
```

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

```
# Wait for 1 hour without consuming resources
context.wait(3600)

# Wait for external callback
approval = context.wait_for_callback(
    lambda callback_id: send_approval_request(callback_id)
)
```

------

当您的函数遇到等待或需要暂停时，Lambda 会保存此检查点日志并停止执行。当需要恢复时，Lambda 会再次调用您的函数并重播检查点日志，从而用存储的值替代已完成的操作。

对于更复杂的工作流，持久性 Lambda 函数还附带高级操作，例如用于并发执行的 `parallel()`、用于处理数组的 `map()`、用于嵌套操作的 `runInChildContext()` 和用于轮询操作的 `waitForCondition()`。有关何时使用每种操作的详细示例和指导，请参阅[示例](durable-examples.md)。

## 调用其他函数
<a name="invoke-concept"></a>

**调用**使持久性函数能够调用其他 Lambda 函数并等待其结果。调用函数在被调用函数执行期间会暂停，从而形成一个检查点，以保存执行结果。这使您能够构建模块化工作流，专用函数可以在其中处理特定任务。

使用 `context.invoke()` 从您的持久性函数中调用其他函数。该调用会被检查点存储，因此如果您的函数在被调用函数执行完毕后中断，它会以存储的结果继续执行，而无需重新调用函数。

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

```
// Invoke another function and wait for result
const customerData = await context.invoke(
  'validate-customer',
  'arn:aws:lambda:us-east-1:123456789012:function:customer-service:1',
  { customerId: event.customerId }
);

// Use the result in subsequent steps
const order = await context.step(async () => {
  return processOrder(customerData);
});
```

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

```
# Invoke another function and wait for result
customer_data = context.invoke(
    'arn:aws:lambda:us-east-1:123456789012:function:customer-service:1',
    {'customerId': event['customerId']},
    name='validate-customer'
)

# Use the result in subsequent steps
order = context.step(
    lambda: process_order(customer_data),
    name='process-order'
)
```

------

调用的函数可以是持久性 Lambda 函数，也可以是标准的 Lambda 函数。如果您调用了持久性函数，则调用函数将等待完整的持久执行完成。这种模式在微服务架构中很常见，在这种架构中，每个函数负责处理特定的领域，从而使您能够通过使用专门的、可复用的函数来构建复杂的工作流。

**注意**  
不支持跨账户调用。被调用的函数必须与调用函数在同一 AWS 账户中。

## 持久性函数配置
<a name="durable-configuration-basic"></a>

持久性函数具有控制执行行为和数据留存的特定配置设置。这些设置独立于标准的 Lambda 函数配置，并且适用于整个持久执行生命周期。

**DurableConfig** 对象用于定义持久性函数的配置：

```
{
  "ExecutionTimeout": Integer,
  "RetentionPeriodInDays": Integer
}
```

### Execution timeout (执行超时)
<a name="durable-execution-timeout"></a>

**执行超时**用于控制持久执行从开始到完成的运行时长。该超时与 Lambda 函数的超时不同，后者用于控制单次函数调用的运行时长。

在其经历检查点、等待和重播的过程中，一个持久执行过程能够跨越多次 Lambda 函数调用。执行超时时间适用于持久执行的总耗时，而非针对每个函数调用而言。

**了解差异**  
Lambda 函数超时时间（最长 15 分钟）会限制您函数的每次调用。持久执行超时（最长 1 年）限制从执行开始到执行完成、失败或超时的总时长。在此期间，由于您的函数会处理步骤、等待和从故障中恢复，可能会被多次调用。

例如，如果您将持久执行超时设置为 24 小时，并将 Lambda 函数超时设置为 5 分钟：
+ 每次函数调用必须在 5 分钟内完成
+ 整个持久执行最多可以运行 24 小时
+ 在这 24 小时内，您的函数可能会被多次调用
+ 等待操作不计入 Lambda 函数超时，但会计入执行超时

在使用 Lambda 控制台、AWS CLI 或 AWS SAM 创建持久性函数时，您可以配置执行超时。在 Lambda 控制台中，选择您的函数，然后选择“配置”“持久执行”。以秒为单位设置执行超时值（默认值：86400 秒/24 小时，最小值：60 秒，最大值：31536000 秒/1 年）。

**注意**  
执行超时和 Lambda 函数超时是不同的设置。Lambda 函数超时控制每次单独调用所能运行的最长时间（最长为 15 分钟）。执行超时控制整个持久执行的总耗时（最长 1 年）。

### 保留期
<a name="durable-retention-period"></a>

**保留期**控制 Lambda 在持久执行完成后将执行历史记录和检查点数据保留的时长。此数据包括步骤结果、执行状态以及完整的检查点日志。

保留期过期后，Lambda 将删除执行历史记录和检查点数据。您无法再检索执行详细信息或重播执行。保留期从执行达到终端状态（SUCCEEDED、FAILED、STOPPED 或 TIMED\$1OUT）时开始。

在使用 Lambda 控制台、AWS CLI 或 AWS SAM 创建持久性函数时，您可以配置保留期。在 Lambda 控制台中，选择您的函数，然后选择“配置”“持久执行”。以天为单位设置保留期值（默认值：14 天，最小值：1 天，最大值：90 天）。

根据您的合规性要求、调试需求和成本考虑因素选择保留期。保留期越长，为调试和审计提供的时间越多，但会增加存储成本。

## 另请参阅
<a name="durable-basic-concepts-see-also"></a>
+ [持久性函数或 Step Functions](durable-step-functions.md)：比较持久性函数与 Step Functions，了解每种方法何时最有效。