AWS CLI `cloudformation wait stack-delete-complete` 详解:用 Waiter 精准等待堆栈删除完成
2026/9/15 19:55:16 网站建设 项目流程

AWS CLIcloudformation wait stack-delete-complete详解:用 Waiter 精准等待堆栈删除完成

【免费下载链接】aws-cliUniversal Command Line Interface for Amazon Web Services项目地址: https://gitcode.com/GitHub_Trending/aw/aws-cli

导读

aws cloudformation wait stack-delete-complete是 AWS CLI 中一个专用于 CloudFormation 堆栈删除场景的等待命令(Waiter)。它不像delete-stack那样直接发起删除请求,而是"原地阻塞":持续轮询DescribeStacksAPI,直到确认目标堆栈已被彻底删除(状态变为DELETE_COMPLETE,或服务端返回堆栈不存在的ValidationError)后才返回,且成功时不产生任何输出。本文以 awscli/examples/cloudformation/wait/stack-delete-complete.rst 为核心,结合 AWS CLI 与 botocore 的 waiter 实现源码,讲解该命令的完整用法、底层轮询机制、成功/失败判定规则以及超时与退出码行为,并给出脚本化实战示例。

命令原型与参数说明

该示例对应的命令形式如下:

aws cloudformation wait stack-delete-complete \ --stack-name "arn:aws:cloudformation:us-west-2:123456789012:stack/my-stack-1234/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"

唯一的必需参数是--stack-name。它既可以像示例中那样传入堆栈的完整 ARN(包含堆栈 ID),也可以传入简单的堆栈名称,例如:

aws cloudformation wait stack-delete-complete --stack-name my-stack

该命令成功后不产生任何输出("This command produces no output"),这与其他 waiter 命令的行为一致——等待成功意味着条件满足,无需向终端打印结果。

等待命令的通用设计:wait 子命令如何被挂载

wait并不是 CloudFormation 服务模型中原生的操作,而是 AWS CLI 在构建命令树时动态注入的通用子命令。在 awscli/customizations/waiters.py 中可以看到其注入逻辑:add_waiters会检查服务命令对象是否带有service_model,然后通过session.get_waiter_model()加载该服务的 waiter 模型(awscli/customizations/waiters.py#L26-L41);只有当模型里确实存在 waiter 定义时,才会把wait命令挂载进命令表:

if waiter_names: command_table['wait'] = WaitCommand(session, waiter_model, service_model)

随后WaiterStateCommandBuilder.build_all_waiter_state_cmds遍历模型中每个 waiter 名称,用xform_name(waiter_name, '-')StackDeleteComplete转换为 CLI 风格的stack-delete-complete子命令(awscli/customizations/waiters.py#L93-L103)。这就是aws cloudformation wait stack-delete-complete命令存在的根源。

底层轮询机制:StackDeleteComplete Waiter 的模型定义

stack-delete-complete的行为完全由 waiter 模型文件 awscli/botocore/data/cloudformation/2010-05-15/waiters-2.json 中的StackDeleteComplete定义驱动:

"StackDeleteComplete": { "delay": 30, "operation": "DescribeStacks", "maxAttempts": 120, "description": "Wait until stack status is DELETE_COMPLETE.", "acceptors": [ { "argument": "Stacks[].StackStatus", "expected": "DELETE_COMPLETE", "matcher": "pathAll", "state": "success" }, { "expected": "ValidationError", "matcher": "error", "state": "success" }, { "argument": "Stacks[].StackStatus", "expected": "DELETE_FAILED", "matcher": "pathAny", "state": "failure" }, ... ] }

各字段含义如下:

字段说明
operationDescribeStacks轮询所调用的底层 API,由 botocore 客户端方法describe_stacks实现
delay30(秒)两次轮询之间的固定休眠间隔
maxAttempts120(次)最大轮询次数,达到后抛出超时错误
acceptors9 个判定器对每次响应进行匹配,决定进入successfailure还是继续waiting

需要特别说明delaymaxAttempts的乘积:30 × 120 = 3600 秒,即理论上最多等待约 1 小时。CloudFormation 删除堆栈通常需要几分钟,因此该配置足以覆盖绝大多数场景;同时也意味着等待命令的最长阻塞时间是相当可观的,脚本化使用时建议在外部再叠加自己的超时控制。

判定器(Acceptor)如何工作

botocore 在 awscli/botocore/waiter.py 中实现了 acceptor 的匹配逻辑,支持pathpathAllpathAnystatuserror五种 matcher:

  • pathAll:用 JMESPath 表达式求值,结果必须是非空列表所有元素都等于expected才匹配(awscli/botocore/waiter.py#L236-L255)。StackDeleteComplete的成功判定即用此 matcher 检查Stacks[].StackStatus全部为DELETE_COMPLETE
  • pathAny:结果列表中至少一个元素等于expected即匹配(awscli/botocore/waiter.py#L257-L276)。删除失败等 failure 判定全部使用此 matcher。
  • error:匹配服务端返回的错误码。当expected为具体的错误码字符串时,精确比对response["Error"]["Code"](awscli/botocore/waiter.py#L292-L312)。

waiter 主循环(Waiter.wait)的逻辑清晰可见(awscli/botocore/waiter.py#L338-L396):每次调用DescribeStacks后,按顺序遍历 acceptor 列表,一旦匹配即切换状态并中断;命中success直接返回,命中failure抛出WaiterError;若所有 acceptor 都未命中则time.sleep(delay)后进入下一轮。

StackDeleteComplete 的完整判定规则

结合 waiters-2.json 中StackDeleteComplete的全部 acceptor,可将判定规则归纳为下表:

状态触发条件语义
success所有返回堆栈的StackStatus均为DELETE_COMPLETE删除成功完成
successDescribeStacks抛出ValidationError(堆栈已不存在)堆栈已被删除,等价于成功
failure任一堆栈状态为DELETE_FAILEDCREATE_FAILEDROLLBACK_FAILEDUPDATE_ROLLBACK_IN_PROGRESSUPDATE_ROLLBACK_FAILEDUPDATE_ROLLBACK_COMPLETEUPDATE_COMPLETE删除过程中出现异常或堆栈处于不应继续等待的终态

其中第二条成功规则是整个命令的精髓:CloudFormation 的删除过程以堆栈从DescribeStacks的响应中消失为终点,此时 API 会返回ValidationError("Stack with id xxx does not exist")。botocore 的NormalizedOperationMethod会把ClientError捕获并转为响应字典交给 acceptor 匹配(awscli/botocore/waiter.py#L89-L97),于是errormatcher 命中,waiter 判定为成功。因此该命令既能捕捉到"状态变为 DELETE_COMPLETE"的时刻,也能捕捉到"堆栈直接消失"的时刻,两者都算删除完成。

完整工作流:先删除、再等待

wait命令本身只做等待,不会发起删除。标准用法是先调用delete-stack触发删除(参见 awscli/examples/cloudformation/delete-stack.rst),再调用 wait 命令阻塞直到删除完成:

aws cloudformation delete-stack --stack-name my-stack aws cloudformation wait stack-delete-complete --stack-name my-stack

delete-stack同样是异步的:命令发起删除请求后立即返回且无输出,真正执行资源释放需要数分钟。wait 命令的价值正是在此——它把"等待异步操作收敛"从手工反复执行describe-stacks的苦力活中解放出来。

失败与超时行为

失败:抛出 WaiterError

当轮询命中任一failureacceptor(如堆栈状态为DELETE_FAILED)时,Waiter.wait会抛出WaiterError。该异常定义于 awscli/botocore/exceptions.py#L477-L484:

class WaiterError(BotoCoreError): """Waiter failed to reach desired state.""" fmt = 'Waiter {name} failed: {reason}'

异常信息会给出匹配到的 acceptor 的说明,例如For expression "Stacks[].StackStatus" we matched expected path: "DELETE_FAILED" at least once(见 awscli/botocore/waiter.py#L180-L199 的explanation生成逻辑)。

超时:达到 maxAttempts

若 120 次轮询(约 1 小时)内始终未进入成功或失败终态,waiter 抛出"Max attempts exceeded"类型的WaiterError(awscli/botocore/waiter.py#L383-L395)。

返回码与脚本判断

根据 awscli/topics/return-codes.rst 的约定:命令成功返回码为0,失败返回码为255。也就是说:

  • 删除完成后 wait 命令返回0
  • 堆栈删除失败或超时,CLI 返回255

WaiterStateCommand.create_help_command中会把操作的output_shape置空(awscli/customizations/waiters.py#L213-L223),从实现层面保证了该命令"无输出"的特性。

实战:脚本化等待与结果判断

由于 wait 命令成功时静默、失败时返回非零退出码,非常适合直接嵌入 Shell 脚本:

# 触发删除并等待完成 aws cloudformation delete-stack --stack-name my-stack if aws cloudformation wait stack-delete-complete --stack-name my-stack; then echo "Stack my-stack deleted successfully." else echo "Stack deletion failed or timed out (exit code $?)." # 可在此调用 describe-stack-events 排查 DELETE_FAILED 的具体原因 fi

几点脚本化建议:

  • 等待成功后不要马上依赖资源消失DELETE_COMPLETE意味着资源释放已完成,但后续操作(如重建同名堆栈)建议仍以 wait 返回为信号,避免竞态。
  • 复用堆栈 ARN 提高精确性:示例中使用完整 ARN 可精确定位堆栈;简单名称在有同名堆栈时会由服务端决定返回哪一个,脚本中建议始终使用 ARN。
  • 失败定位:wait 失败后,可用aws cloudformation describe-stack-events --stack-name my-stack查看最近的StackStatus与事件,定位DELETE_FAILED的根因(例如依赖的 S3 桶非空、IAM 角色被引用等)。

与其他 wait 子命令的关系

CloudFormation 服务共定义了 9 个 waiter,对应wait下的 9 个子命令,全部由同一套 waiters-2.json 模型驱动,示例文档位于 awscli/examples/cloudformation/wait/ 目录:

wait 子命令底层操作成功条件(简述)
stack-existsDescribeStacks返回 HTTP 200
stack-create-completeDescribeStacks状态为CREATE_COMPLETE
stack-delete-completeDescribeStacks状态为DELETE_COMPLETE或抛出ValidationError
stack-update-completeDescribeStacks状态为UPDATE_COMPLETE
stack-import-completeDescribeStacks状态为IMPORT_COMPLETE
stack-rollback-completeDescribeStacks状态为UPDATE_ROLLBACK_COMPLETE
change-set-create-completeDescribeChangeSet变更集状态为CREATE_COMPLETE
stack-refactor-create-completeDescribeStackRefactor重构状态为CREATE_COMPLETE
stack-refactor-execute-completeDescribeStackRefactor执行状态为EXECUTE_COMPLETE
type-registration-completeDescribeTypeRegistration注册进度为COMPLETE

同一套wait机制也适用于 S3、EC2 等服务(例如aws s3api wait bucket-existsaws ec2 wait instance-running),理解stack-delete-complete的实现,就等于理解了所有 AWS CLI waiter 命令的通用原理。

小结

aws cloudformation wait stack-delete-complete通过DescribeStacks每 30 秒轮询一次、最多 120 次,将"堆栈状态变为DELETE_COMPLETE"或"堆栈从 API 响应中消失(ValidationError)"判定为成功,将DELETE_FAILED等异常终态判定为失败。整个轮询与判定逻辑由 awscli/botocore/data/cloudformation/2010-05-15/waiters-2.json 的模型配置和 awscli/botocore/waiter.py 的通用实现共同支撑,命令本身由 awscli/customizations/waiters.py 动态挂载。在自动化脚本中,配合delete-stack使用并以退出码判断结果,即可稳健地编排"删除资源 → 确认完成 → 继续后续步骤"的完整流程。

【免费下载链接】aws-cliUniversal Command Line Interface for Amazon Web Services项目地址: https://gitcode.com/GitHub_Trending/aw/aws-cli

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询