PAYATHON 2026

AWS Lambda 如何暂停和恢复容器执行?

数据阿明

AWS Lambda 可以在等待下一次调用时冻结整个执行环境,之后再恢复并复用它。GET /runtime/invocation/next 是阻塞式调用,运行时通过它声明自己已准备好接收下一次事件。

普通按需 Lambda 的执行费用按配置的内存和计费执行时长计算,计费时长并非只指进程实际占用 CPU 的时间。以下讨论这种模式下的自定义运行时。AWS Lambda 定价说明

没有新调用时,GET 请求会怎样?

运行时发送:

GET /2018-06-01/runtime/invocation/next

没有事件可交付时,请求会等待。它通过长轮询获取事件,正常流程无需不断接收“稍后重试”响应。

AWS 明确要求不要给这个 GET 请求设置客户端超时,因为返回可能延迟,等待期间运行时也可能被冻结。这并不保证连接永久有效:连接故障和执行环境终止仍需按错误路径处理。Runtime API 文档

为什么等待期间不累计执行费用?

自定义运行时通过 /next 发出处理完成信号,通常按以下顺序运行:

初始化
  → GET /next,声明准备就绪
  → 收到调用事件
  → 执行业务逻辑
  → POST /response 或 /error
  → GET /next,声明本次处理结束
  → 等待下一次事件

提交 /response 后,自定义运行时还可以继续执行代码,直到再次请求 /next 才结束本次处理。这段时间不能当作免费的后台执行时间。AWS 官方示例也采用了这一流程。AWS 自定义运行时说明

普通按需环境完成本次处理并进入冻结等待后,不会因为 /next 请求尚未返回而持续累计调用执行时长。调用处理期间等待数据库、网络或 sleep,仍会占用执行时长。初始化代码也可能计入费用;启用 Provisioned Concurrency 时,还存在单独的容量费用。AWS Lambda 定价说明

是否依赖阻塞 system call?其他线程还能运行吗?

阻塞 socket 读取可以让等待线程暂时不占用 CPU,但 Lambda 的冻结行为由服务管理,不要求应用自行确保所有线程都阻塞。

当运行时和所有已注册扩展都通过各自的 Next 请求表示完成,且没有待处理事件时,Lambda 会冻结执行环境。冻结会影响环境中的后台线程和进程;如果环境被复用,未完成的后台工作可能随之恢复。线程是否设置为 daemon,也不能保证它持续运行。执行环境生命周期文档

不能靠另一个忙循环线程在两次调用之间持续计算。需要保证完成的工作,应在声明本次处理结束前完成。

接口文档没有对冻结所用的具体内核机制、内存是否换出以及是否生成磁盘 checkpoint 作出可依赖的实现承诺,不能从阻塞 GET 请求推导这些细节。

是否会保存容器,数天后继续运行?

如果环境得以保留,Lambda 可以恢复它,内存中的对象也可能继续使用。环境复用没有固定的保留时长保证,服务可以回收环境,下次调用可能需要重新初始化。

因此,不能依赖某个进程一定在数天后原地恢复,也不能将普通 freeze/thaw 当作持久化 checkpoint。需要长期保存的业务状态应写入持久存储。执行环境复用说明

迟迟不提交结果,Lambda 会怎样处理?

调用超过函数配置的 timeout 时,Lambda 会使调用超时,关闭运行时并重置执行环境。如果该环境随后用于新调用,运行时和扩展会重新初始化,自定义运行时的 bootstrap 也会重新执行。

这与等待下一次事件时挂起的 /next 请求不同:前者是正在处理的调用超过期限,后者是已准备好接收新事件。不能依赖超时后继续提交结果或完成清理。调用失败与环境重置说明

自定义运行时应如何编写循环?

收到事件后,依次处理业务、提交结果,并立即请求下一次事件。下面用 Python 和 requests 展示成功路径,业务逻辑将输入原样返回:

import os
import requests

base_url = (
    f"http://{os.environ['AWS_LAMBDA_RUNTIME_API']}"
    "/2018-06-01/runtime"
)

while True:
    invocation = requests.get(
        f"{base_url}/invocation/next",
        timeout=None,
    )
    invocation.raise_for_status()

    request_id = invocation.headers['Lambda-Runtime-Aws-Request-Id']
    headers = {}
    invocation_id = invocation.headers.get('Lambda-Runtime-Invocation-Id')
    if invocation_id is not None:
        headers['Lambda-Runtime-Invocation-Id'] = invocation_id

    result = invocation.json()
    response = requests.post(
        f"{base_url}/invocation/{request_id}/response",
        json=result,
        headers=headers,
        timeout=None,
    )
    response.raise_for_status()

示例省略了初始化失败、业务异常和通信错误处理。完整运行时还需按 Runtime API 协议向 /runtime/init/error 或 /runtime/invocation/{requestId}/error 报告对应错误。调用的截止时间可从 Lambda-Runtime-Deadline-Ms 响应头读取,用它控制业务操作的剩余时间;不要给等待新事件的 /next 套用同一套超时逻辑。Runtime API 接口参考

备注:内容仅供参考。