异步解决的是占用问题
长耗时任务(备份、打补丁、编译)会占住一个并发窗口,让后续任务只能干等。异步机制给任务设一个最长运行时间并把控制权立刻交回,控制节点可以继续做别的事,稍后再取结果。注意它不会让任务本身更快:收益来自窗口被释放,可以在等待期间推进别的批次与别的任务。
基本信息
| 两个参数 | 最长运行时间与轮询间隔(间隔为 0 表示不等结果、直接往下走) |
|---|---|
| 结果查询 | 用异步状态查询模块按任务标识取回结果 |
| 运行位置 | 任务仍在目标机执行,产物与日志留在目标机指定目录 |
| 适用模块 | 适合命令类与长耗时操作;前提是目标机与连接方式支持异步 |
| 限制 | 检查模式与异步存在已知限制,实际行为以官方文档为准 |
| 配套 | 善后重试与失败收敛策略,避免只发起不检查 |
典型使用场景
- 打补丁与大规模升级:单机耗时长,用异步释放窗口,其他主机同步推进
- 数据库备份与压缩:避免整个剧本被一个备份任务卡住
- 大批量文件处理:多台主机并行处理时不让慢机器拖住全局节奏
- 独立于剧本的维护动作:发起后立即继续执行后续无关步骤
- 与等待机制配合:先发起长任务,随后在需要结果的地方再查询
- 并发受限环境:窗口数很少时,用异步让长任务不占用额外窗口
发起与回收结果
发起与回收结果
- name: 发起长耗时任务(不等结果)
ansible.builtin.command: /usr/local/bin/full-backup.sh
async: 3600 # 该任务最长运行 3600 秒
poll: 0 # 不等待,立即返回
register: backup_job
changed_when: true
- name: 在真正需要结果处再查询一次
ansible.builtin.async_status:
jid: "{{ backup_job.ansible_job_id }}"
register: backup_result
until: backup_result.finished
retries: 60
delay: 30
- name: 用断言判断最终结果
ansible.builtin.assert:
that:
- backup_result.finished == 1
- backup_result.rc | default(1) == 0
fail_msg: "备份任务未成功完成:{{ backup_result.stderr | default('') }}"
- name: 短任务也可以异步但同步等待(间隔 5 秒轮询)
ansible.builtin.command: /usr/local/bin/repair-index.sh
async: 600
poll: 5取值与影响
| 组合 | 行为 | 适用 |
|---|---|---|
| poll 大于 0 | 间隔轮询,仍在本任务内等结果 | 希望保留失败立刻暴露,同时避免长连接占用 |
| poll 等于 0 | 发起即返回,后续需自行查询 | 真正希望并行推进其它任务的场景 |
| 运行时间给得过短 | 任务被强制中断,留下半完成状态 | 需按实测最坏耗时设置 |
| 运行时间给得过长 | 故障时等待期拉长 | 配合查询与断言可接受 |
| 忘记查询结果 | 失败被静默吞掉,剧本显示成功 | 必须配置查询与断言 |
异步的“不等结果”意味着错误不再自动中断流程。凡使用立即返回的写法,都应在后面安排一次结果查询与断言,把失败重新变成失败;否则异步就成了掩盖问题的工具。
异步任务被强制中断时会留下不完整的中间状态(备份文件残缺、进程被杀)。对这类任务要设计可重入的步骤或清理动作,并在中断后重新执行前先确认现场,而不是直接重跑。
什么时候不用异步
如果任务很短或者后面的步骤必须依赖它的结果,异步只会增加复杂度:同步等待与异步加轮询的总时长基本一致,却多了结果查询与失败判定的代码。只有在“等待期间确实能做别的事”时,异步才有收益。