You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ansible角色中rescue-handler与run_once结合执行异常问询

Ansible include_role 中 run_once 任务重复执行的原因

问题复现

重构Ansible playbook时遇到异常:通过include_role引入包含rescue处理块和run_once任务的角色时,run_once任务会执行两次。

目录结构

|_ showcase.yml
\_ sc_role
    \_ tasks
        |_ main.yml
        \_ block-with-rescue.yml

代码内容

  • showcase.yml
---
- hosts: [a, b]
  gather_facts: false
  tasks:
  - include_role:
      name: sc_role
  • sc_role/tasks/main.yml
---
- include_tasks:
    file: block-with-rescue.yml
- debug:
    msg: "run_once task"
  run_once: true
  delegate_to: localhost
  • sc_role/tasks/block-with-rescue.yml
---
- block:
    - debug:
        msg: "Provoke exception {{ u_n_d_e_f_i_n_e_d }}"
      when: inventory_hostname == "a"
  rescue:
    - debug:
        msg: "rescue task"

执行现象

主机a触发block异常后进入rescue块,主机b先执行run_once任务;待主机a完成rescue处理后,会再次执行run_once任务,导致任务重复执行。

原因分析

这个现象的核心是include_role的执行机制、run_once的跟踪逻辑,以及rescue块对执行流的影响共同作用的结果:

  1. include_role的独立执行流特性
    使用include_role时,角色的任务会嵌入到每个主机的独立执行流中,也就是说每个主机都会完整走一遍角色的任务流程,而非像roles关键字那样,先把角色任务合并到play的全局任务列表,再按批次处理所有主机的同一步任务。

  2. run_once的全局跟踪依赖执行上下文连续性
    run_once: true的作用是让任务在整个play中仅执行一次,由第一个执行到该任务的主机触发,执行后会标记任务为已完成。但这个标记的识别依赖于任务执行流的连续性——如果执行流被异常中断并恢复,跟踪逻辑可能出现偏差。

  3. rescue块导致的执行流中断与恢复
    主机a执行block时触发异常,进入rescue块处理,此时Ansible会暂停角色任务的正常执行流程。当rescue处理完成后,主机a的执行流回到角色任务序列,继续执行后续的run_once任务。此时由于之前的异常中断,Ansible内部没有正确识别到该任务已经被主机b执行过,而是将其视为主机a执行流中首次遇到的任务,因此再次触发执行。

规避方案的原理补充

已知的两种规避方法本质上都是改变了任务的执行上下文:

  • 用roles段引入角色:角色任务会被预先合并到play的全局任务列表,所有主机先完成角色中的include_tasks(含rescue处理),再统一处理run_once任务,自然只会执行一次。
  • 将run_once任务移到include_role之后:该任务成为play的全局任务,不再属于角色内部的主机独立执行流,因此严格遵循run_once的全局唯一执行逻辑。

内容的提问来源于stack exchange,提问作者dheuvels

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 19:16:04