Sandbox 深休眠(完整会话恢复)

更新时间:
复制为 MD 格式

Sandbox 深休眠通过 PauseSession 和 ResumeSession API,将 Sandbox 会话的实例状态(内存、文件系统、进程)保存为快照并销毁实例,需要时基于快照恢复。暂停期间不产生 CPU 和内存费用,适用于需要长期保留环境状态但不持续运行的场景。

功能介绍

Sandbox 深休眠基于函数计算 Session 能力,调用 PauseSession 后,系统将会话关联实例的完整运行状态保存为快照并销毁实例;调用 ResumeSession 后,系统基于快照将实例恢复至新执行环境,回到暂停前的状态。

成本影响:暂停后实例被销毁,不产生 CPU 和内存费用。相比浅休眠(Idle 状态仍收取内存费用),深休眠可进一步降低长期持有 Sandbox 实例的成本。

典型场景

  • AI Sandbox 开发环境:Sandbox 安装依赖和工具后,通过深休眠保存环境状态,下次使用时快速恢复,无需重新初始化。

  • 按需启停的长周期任务:长时间保留工作状态但不持续运行,例如可中断后继续的数据处理任务。

使用前提

重要

Sandbox 深休眠目前为白名单功能,默认不开放。如需使用,请提交工单申请开通。

函数需满足以下条件:

配置项

要求

说明

会话亲和

必须开启

支持 HeaderField 亲和或 Cookie 亲和,不支持 MCP 亲和类型

实例隔离

必须开启会话隔离

确保一个会话对应一个独立实例(Sandbox 模式)

运行时类型

自定义镜像(Custom Container)

不支持内置运行时和自定义运行时

实例规格

仅支持 CPU 实例

不支持 GPU 实例

CPU / 内存规格

无特殊限制

按需选择

会话亲和和会话隔离的配置方法,参见会话亲和通用限制及原理说明HeaderField 亲和配置

功能限制与约束

暂停与恢复行为

阶段

行为说明

暂停后

实例被销毁,不产生 CPU 和内存费用。Session 不接受函数调用请求。通过 GetSession / ListSessions 可查询 Paused 状态的 Session,但通过 ListInstances 无法查询已销毁的实例。

恢复后

Session TTL 不重置,仍从原始创建时间累计。恢复后的行为如下:

  • 剩余 TTL 继续扣减暂停期间的时长。例如 TTL 为 24 小时,运行 6 小时后暂停,暂停 2 小时后恢复,剩余 TTL 为 16 小时(24 - 6 - 2 = 16)。

  • 可继续接受函数调用。

  • 暂停前的网络连接(WebSocket、gRPC 长连接)不会恢复,需重新建立。

  • 支持反复暂停和恢复。

操作与状态约束

操作

允许的 Session 状态

说明

PauseSession

Active

仅 Active 状态可暂停

ResumeSession

Paused

仅 Paused 状态可恢复

UpdateSession

不允许

Pausing、Paused、Resuming 状态均不允许更新

DeleteSession

仅 Paused 状态允许

Pausing 和 Resuming 中间状态不允许删除

InvokeFunction

不允许

Pausing、Paused、Resuming 状态均不接受新请求

函数版本相关限制

  • 非 LATEST 版本:Session 关联的函数版本必须已开启会话亲和 + 会话隔离,否则不支持 PauseSession 和 ResumeSession。

  • LATEST 版本

    • 必须开启会话亲和 + 会话隔离。

    • PauseSession 限制:如果 Session 关联的实例上存在多个 Session,不允许执行 PauseSession。

    • ResumeSession 限制:如果暂停后、恢复前,LATEST 版本的函数配置发生变更(元数据版本变化),不允许执行 ResumeSession。

操作步骤

安装 SDK 依赖

安装 Go SDK 依赖:

go get github.com/alibabacloud-go/darabonba-openapi/v2/client
go get github.com/alibabacloud-go/fc-20230330/client
go get github.com/alibabacloud-go/tea/dara
go get github.com/alibabacloud-go/tea/tea

初始化 FC Client

初始化函数计算客户端,将 RegionId 和 Endpoint 替换为实际值。AccessKey 通过环境变量获取。

package main

import (
    "fmt"
    "os"

    openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
    fc "github.com/alibabacloud-go/fc-20230330/client"
    "github.com/alibabacloud-go/tea/dara"
    "github.com/alibabacloud-go/tea/tea"
)

func createClient() (*fc.Client, error) {
    return fc.NewClient(&openapi.Config{
        RegionId:        tea.String("cn-shanghai"),          // 替换为实际 Region
        AccessKeyId:     tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")),
        AccessKeySecret: tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")),
        Endpoint:        tea.String("<账号ID>.cn-shanghai.fc.aliyuncs.com"), // 替换为实际 Endpoint
    })
}

暂停会话(PauseSession)

将 Active 状态的会话暂停,保存实例快照后销毁实例。

API 请求语法

PUT /2023-03-30/functions/{functionName}/sessions/{sessionId}/pause

Go SDK 示例

func pauseSession(client *fc.Client, functionName, sessionId *string) (*fc.PauseSessionResponse, error) {
    return client.PauseSessionWithOptions(
        functionName,
        sessionId,
        &fc.PauseSessionRequest{},
        nil,
        &dara.RuntimeOptions{},
    )
}

// 调用示例
func main() {
    client, err := createClient()
    if err != nil {
        panic(err)
    }

    functionName := tea.String("my-sandbox-function")
    sessionId := tea.String("my-session-id")

    resp, err := pauseSession(client, functionName, sessionId)
    if err != nil {
        fmt.Printf("PauseSession 失败: %v\n", err)
        return
    }
    fmt.Printf("PauseSession 成功,Session 状态: %s\n", tea.StringValue(resp.Body.SessionStatus))
}
说明

调用成功后,Session 状态经历 Active → Pausing → Paused。可通过 GetSession 查询当前状态,确认 Session 已进入 Paused 状态。

如果 Session 关联了函数别名或特定版本,通过 Qualifier 参数指定:

resp, err := client.PauseSessionWithOptions(
    functionName,
    sessionId,
    &fc.PauseSessionRequest{
        Qualifier: tea.String("my-alias"),
    },
    nil,
    &dara.RuntimeOptions{},
)

详细参数说明参见 PauseSession - 暂停会话 API 文档

恢复会话(ResumeSession)

将 Paused 状态的会话恢复,基于快照将实例还原至新执行环境。

API 请求语法

PUT /2023-03-30/functions/{functionName}/sessions/{sessionId}/resume

Go SDK 示例

func resumeSession(client *fc.Client, functionName, sessionId *string) (*fc.ResumeSessionResponse, error) {
    return client.ResumeSessionWithOptions(
        functionName,
        sessionId,
        &fc.ResumeSessionRequest{},
        nil,
        &dara.RuntimeOptions{},
    )
}

// 调用示例
func main() {
    client, err := createClient()
    if err != nil {
        panic(err)
    }

    functionName := tea.String("my-sandbox-function")
    sessionId := tea.String("my-session-id")

    resp, err := resumeSession(client, functionName, sessionId)
    if err != nil {
        fmt.Printf("ResumeSession 失败: %v\n", err)
        return
    }
    fmt.Printf("ResumeSession 成功,Session 状态: %s\n", tea.StringValue(resp.Body.SessionStatus))
}
说明

调用成功后,Session 状态经历 Paused → Resuming → Active。可通过 GetSession 查询当前状态,确认 Session 已恢复为 Active。恢复后,暂停前的网络连接(WebSocket、gRPC 长连接等)不会自动恢复,客户端需重新建立连接。

详细参数说明参见 ResumeSession - 恢复会话 API 文档

查询会话状态

通过 GetSession 查询会话当前状态:

func getSession(client *fc.Client, functionName, sessionId *string) (*fc.GetSessionResponse, error) {
    return client.GetSession(functionName, sessionId, &fc.GetSessionRequest{})
}

完整使用流程示例

以下 Go SDK 示例演示从创建会话到暂停、恢复、删除的端到端流程:

package main

import (
    "fmt"
    "os"

    openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
    fc "github.com/alibabacloud-go/fc-20230330/client"
    "github.com/alibabacloud-go/tea/dara"
    "github.com/alibabacloud-go/tea/tea"
)

func main() {
    // 1. 初始化客户端
    client, err := fc.NewClient(&openapi.Config{
        RegionId:        tea.String("cn-shanghai"),
        AccessKeyId:     tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")),
        AccessKeySecret: tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")),
        Endpoint:        tea.String("<账号ID>.cn-shanghai.fc.aliyuncs.com"),
    })
    if err != nil {
        panic(err)
    }

    functionName := tea.String("my-sandbox-function")
    headerKey := "x-session-id"

    // 2. 首次调用函数,自动创建 Session
    invokeResp, err := client.InvokeFunctionWithOptions(
        functionName,
        &fc.InvokeFunctionRequest{},
        &fc.InvokeFunctionHeaders{},
        &dara.RuntimeOptions{},
    )
    if err != nil {
        panic(err)
    }
    // 从响应头中获取 Session ID
    sessionId := invokeResp.Headers[headerKey]
    fmt.Printf("Session 已创建,Session ID: %s\n", tea.StringValue(sessionId))

    // 3. 使用 Session 调用函数(通过 Sandbox 执行操作)
    _, err = client.InvokeFunctionWithOptions(
        functionName,
        &fc.InvokeFunctionRequest{},
        &fc.InvokeFunctionHeaders{
            CommonHeaders: map[string]*string{
                headerKey: sessionId,
            },
        },
        &dara.RuntimeOptions{},
    )
    if err != nil {
        panic(err)
    }
    fmt.Println("函数调用成功")

    // 4. 暂停会话(保存快照,销毁实例)
    pauseResp, err := client.PauseSessionWithOptions(
        functionName,
        sessionId,
        &fc.PauseSessionRequest{},
        nil,
        &dara.RuntimeOptions{},
    )
    if err != nil {
        panic(err)
    }
    fmt.Printf("PauseSession 成功,状态: %s\n", tea.StringValue(pauseResp.Body.SessionStatus))

    // 5. 一段时间后,恢复会话
    resumeResp, err := client.ResumeSessionWithOptions(
        functionName,
        sessionId,
        &fc.ResumeSessionRequest{},
        nil,
        &dara.RuntimeOptions{},
    )
    if err != nil {
        panic(err)
    }
    fmt.Printf("ResumeSession 成功,状态: %s\n", tea.StringValue(resumeResp.Body.SessionStatus))

    // 6. 继续使用 Session 调用函数
    _, err = client.InvokeFunctionWithOptions(
        functionName,
        &fc.InvokeFunctionRequest{},
        &fc.InvokeFunctionHeaders{
            CommonHeaders: map[string]*string{
                headerKey: sessionId,
            },
        },
        &dara.RuntimeOptions{},
    )
    if err != nil {
        panic(err)
    }
    fmt.Println("恢复后函数调用成功,环境状态与暂停前一致")

    // 7. 使用完毕,删除会话
    _, err = client.DeleteSessionWithOptions(
        functionName,
        sessionId,
        &fc.DeleteSessionRequest{},
        nil,
        &dara.RuntimeOptions{},
    )
    if err != nil {
        panic(err)
    }
    fmt.Println("Session 已删除")
}

会话状态流转

开启深休眠功能后,Session 在原有生命周期基础上新增 Pausing、Paused、Resuming 三个状态。

当前状态

触发操作 / 事件

目标状态

(初始)

CreateSession 或 InvokeFunction

Active

Active

PauseSession

Pausing

Pausing

快照完成,实例销毁

Paused

Paused

ResumeSession

Resuming

Resuming

实例恢复完成

Active

Active

TTL 超时或 Idle 超时

Expired

Active

DeleteSession

Deleted

Paused

DeleteSession

Deleted

状态

含义

是否计费

Active

会话活跃,实例就绪,可处理请求

是(按实例运行计费)

Pausing

正在保存快照,实例 CPU 已冻结

是(快照过程中仍计费)

Paused

快照已保存,实例已销毁

否(不产生 CPU 和内存费用)

Resuming

正在从快照恢复实例

是(恢复过程中开始计费)

Expired

会话过期(TTL 超时或 Idle 超时)

Deleted

用户主动删除会话

常见问题

暂停后的 Session 是否会自动过期?

会。Session TTL 在暂停期间仍继续累计。如果 Paused 状态下达到 TTL 上限,Session 自动过期。建议暂停前确认剩余 TTL 是否满足需求。

恢复后 Session TTL 如何计算?

TTL 不因 ResumeSession 重置,始终从 Session 创建时间计算。例如,TTL 为 24 小时,创建 6 小时后暂停,暂停 2 小时后恢复,剩余 TTL 为 16 小时(24 - 6 - 2 = 16)。

是否支持多次暂停和恢复?

支持。Active 状态可执行 PauseSession,Paused 状态可执行 ResumeSession,可反复操作。

LATEST 版本函数修改配置后能否恢复?

不能。在 PauseSession 之后、ResumeSession 之前修改 LATEST 版本的函数配置(导致元数据版本变化),系统将拒绝 ResumeSession 并返回错误。

即使先恢复再修改配置,已恢复的实例仍使用暂停前的旧配置。如需使用最新配置,删除当前会话并创建新会话。

暂停时实例上有正在执行的请求会怎样?

PauseSession 后系统立即冻结实例 CPU。正在执行的请求将因 CPU 冻结而超时失败。建议确认实例上无活跃请求后再执行暂停。

暂停后通过 GetSession 能查询哪些信息?

可查询 Session 的完整配置信息(Session ID、函数名称、状态等)。由于实例已销毁,ListInstances 无法查询对应实例信息。