Salt 异步批处理任务管理实战:salt.runners.batch Runner 的 status / list_active / stop 深入解析
运维配置管理后端【免费下载链接】saltSoftware to automate the management and configuration of infrastructure and applications at scale.项目地址https://gitcode.com/gh_mirrors/sa/salt点击查看免费下载salt.runners.batch是 Salt 主控端master上用于管理与巡检异步批处理async batch任务的 Runner 模块它围绕status、list_active、stop三个命令让运维人员能够在salt -b批处理模式脱离前台之后仍然掌握每个批量任务的状态、清单与停止手段。本文以该模块的官方文档为骨架结合仓库内salt/utils/batch_state.py、salt/utils/batch_manager.py、salt/utils/batch_output.py等实现源码与单元测试讲清三个命令的用法、返回值、底层状态机与事件驱动原理帮助你把它直接用于生产环境的批量任务管控。一、Runner 定位异步批处理任务的控制台Salt 的批处理batch模式通过salt -b即--batch-size将目标 minion 按固定窗口分批执行避免一次性打满全网。传统上批处理由 CLI 前台驱动同步模式但从 RFC-0002 引入异步批处理支持见 changelog/60269.added.md后批量任务的编排可以被卸载到 master 的事件循环上由 master 侧的BatchManager进程驱动。salt.runners.batch源码见 salt/runners/batch.py就是面向这个异步体系暴露给运维人员的 Runner 接口。它的模块 docstring 直接给出了四个典型用法# 查询某个异步 batch 任务的状态 salt-run batch.status 20240610120000000000 # 列出所有活跃的异步 batch 任务 salt-run batch.list_active # 停止一个正在运行的异步 batch 任务优雅排空 salt-run batch.stop 20240610120000000000 # 停止并同时终止在途 minion 上的任务 salt-run batch.stop 20240610120000000000 killTrue模块通过__virtualname__ batch声明虚拟名因此所有函数都以batch.function形式被 Runner 装载调用。Runner 本身不做任何文件写入——状态查询走salt.utils.batch_state的只读接口停止请求则通过 master 事件总线投递给BatchManager由后者统一完成持久化与推进职责边界非常清晰。二、三个核心命令的完整说明2.1 batch.status查询单个 batch 任务状态def status(jid): Return the current status of an async batch job. ... :param str jid: The batch JID to query. :returns: Summary dict or None. :rtype: dict or None 参数jid为批处理任务统一的任务 IDJID例如20240610120000000000。行为从该 JID 对应的作业缓存目录中读取.batch.p状态文件返回一个扁平化的 summary 字典。返回值若 JID 不存在或该 JID 从未是异步 batch没有.batch.p或缓存已被清理则返回None。调用示例salt-run batch.status 202406101200000000002.2 batch.list_active列出全部活跃 batchdef list_active(): Return a list of all active (non-halted) async batch jobs. ... :returns: List of batch summary dicts. :rtype: list 读取cachedir/batch_active.p活跃索引逐个读取每个 JID 的.batch.p并生成 summary 列表。容错设计对于.batch.p缺失或不可读的条目会静默丢弃——文档与源码明确指出Maintenancemaster 维护进程会在下一轮收敛清理这些脏索引因此 Runner 无需自行删改。JID 按字典序排序输出便于阅读与对比。调用示例salt-run batch.list_active2.3 batch.stop停止运行中的 batchdef stop(jid, killFalse): Stop a running async batch job. ... :param str jid: The batch JID to stop. :param bool kill: When True, also terminate in-flight minion jobs via saltutil.kill_job. :rtype: bool 默认killFalse是优雅排空只停止后续子批次的发布halt 进一步调度但保留在途 minion 任务的运行这些任务的返回仍会通过正常的salt/job/jid/ret/minion路径写入作业缓存进度不会丢失。killTrue为强制终止在触发 halt 事件之前先向该 batch 当前处于 active在途状态的 minion 发布saltutil.kill_job将参数jid以tgt_typelist形式异步下发。对已经完成任务的 minion 是无害的 no-op对应源码_kill_active_minions只取state[active]中的 minion。返回值JID 未知或该 batch 已经处于halted状态时返回False否则返回True。两种调用方式# 优雅排空后续批次不再发布在途任务跑完 salt-run batch.stop 20240610120000000000 # 强制终止先 kill 在途 minion 任务再停止调度 salt-run batch.stop 20240610120000000000 killTrue2.4 summary 返回结构一个扁平、稳定的字段契约status与list_active返回的每个 summary 都由_summary()统一构造见 salt/runners/batch.py。源码注释明确说明刻意设计为扁平映射方便salt-run --outjson消费并且跨小版本保持稳定。字段含义如下字段类型含义jidstr批处理任务 JIDfunstr批处理执行的执行模块函数如test.pingtgtstr目标表达式tgt_typestr目标匹配类型如globtotalint全部目标 minion 数all_minions长度completedint已完成doneminion 数activeint在途activeminion 数pendingint待调度pendingminion 数failedint失败failedminion 数batch_sizeint每批次大小haltedbool是否已中止异常终止halted_reasonstr/None中止原因如failhard、stopdriverstr驱动方式cli同步 CLI 驱动或master异步 BatchManager 驱动userstr发起 batch 的用户createdfloat创建时间戳last_progressfloat最近一次推进时间戳age_secondsfloat/None距最近推进的秒数now - last_progress无进度记录时为None实际输出效果JSON 模式下约 18 个字段salt-run --outjson batch.status 20240610120000000000{ jid: 20240610120000000000, fun: state.apply, tgt: web*, tgt_type: glob, total: 200, completed: 80, active: 20, pending: 100, failed: 0, batch_size: 20, halted: false, halted_reason: null, driver: master, user: root, created: 1718107200.0, last_progress: 1718107350.0, age_seconds: 30.0 }三、底层原理BatchState 状态机与两级持久化Runner 之所以轻是因为所有状态推进都落在salt.utils.batch_state见 salt/utils/batch_state.py这个与 I/O 完全解耦的纯状态机上。BatchState是一个普通 dict包含all_minions、pending、active、done、failed、wait、batch_size、failhard、batch_wait、timeout、gather_job_timeout、halted、halted_reason、driver、user等键。progress_batch()是推进核心消费一批新返回后返回一个Actionnamedtuple携带publish下一步要发布的 minion 列表、finished_minions、timed_out_minions、halted、halted_reason。其内部按固定顺序完成处理返回 → 判定 failhard → 处理驱动上报超时 → 内部超时清扫 → 剪除过期wait记录 → 按batch_size - len(active) - len(wait)的空闲槽位从pending弹出新 minion 组成下一子批次。3.1 .batch.p 与 batch_active.p状态通过两级文件持久化均由salt.utils.batch_state提供读写接口cachedir/jobs/jhash[:2]/jhash[2:]/jid/.batch.p单个 batch 的完整状态快照。目录结构由salt.utils.jid.jid_dir()按 JID 的哈希分片生成见 salt/utils/jid.py。写入使用salt.utils.atomicfile.atomic_open()原子写读者永远不会读到半截数据读取失败文件损坏时返回None由调用方按不可恢复处理Maintenance 最终会清理。cachedir/batch_active.p当前活跃 batch JID 集合的索引同样原子写入。add_to_active_index/remove_from_active_index是读-改-写模式正常运行时BatchManager是唯一写者竞态窗口可忽略。3.2 事件驱动的 Runner 与 BatchManager 协作batch.stop之所以能生效靠的是 master 事件总线。Runner 通过salt.utils.event.get_master_event()取得事件句柄投递salt/batch/jid/stop事件携带{jid: jid, reason: stop}随后由BatchManager._handle_stop()完成真正的状态修改置haltedTrue、写入.batch.p、发出salt/batch/jid/halted、并从活跃索引中退役该 JID见 salt/utils/batch_manager.py。BatchManager是 masterProcessManager启动的SignalHandlingProcess与 Maintenance、Reactor 引擎并列见 salt/master.py。它空闲时阻塞在get_event(waitloop_interval)上loop_interval由 master 配置batch_manager_loop_interval控制默认 5 秒每次醒来无论有无事件都会执行一次_tick()巡检推进超时检测与batch_wait过期。3.3 事件词汇表salt.utils.batch_output见 salt/utils/batch_output.py集中定义了全部salt/batch/*事件标签与载荷构造代码库中其它模块不应手工拼装这些标签事件标签含义salt/batch/jid/new新异步 batch 注册salt/batch/jid/progress状态推进含空闲心跳salt/batch/jid/complete全部 minion 结清且未中止salt/batch/jid/halted异常终止failhard / stop / 损坏 / 陈旧salt/batch/jid/recoverMaintenance 发现陈旧 batch 时触发恢复salt/batch/jid/stopbatch.stopRunner 发出的停止请求四、深入stop 的两种模式在源码中的真实路径batch.stop的完整链路值得展开因为它同时演示了事件投递与kill 发布两条路径前置检查read_batch_state(jid, __opts__)读不到状态日志batch.stop: no batch state found for jid ...或state[halted]为真时直接返回False且不会发出任何事件。killTrue 分支_kill_active_minions(state)取sorted(state[active].keys())为空则直接跳过否则用salt.client.get_local_client()异步下发local.cmd_async( list(minion_ids), # 在途 minion 列表 saltutil.kill_job, # 复用现有按 minion 取消原语 arg[state[jid]], # 要杀掉的 batch JID tgt_typelist, )该原语的执行端是salt/modules/saltutil.py中的kill_job因此不新增任何取消管道完全复用既有能力。异常会被捕获并记录日志不会中断后续 halt 流程。 3.halt 投递以listenFalse打开 master 事件句柄firesalt/batch/jid/stop随后BatchManager负责原子 halt 写入、发salt/batch/jid/halted并退役索引Runner 返回True。值得注意同步 CLI 驱动的 batchdrivercli同样能被这三个 Runner 看到。3008.2 的发布说明见 doc/topics/releases/3008.2.md记录了 issue #69418 的修复sync CLI 不再直接写 master 的cachedir否则以 root 运行的 CLI 会以错误属主预建 JID 目录导致 master 侧local_cache.prep_jid触发PermissionError而是把每次状态迁移作为salt/batch/jid/{new,progress,complete,halted}事件托运给 master 侧的BatchManager代写。因此非 root master root CLI 的部署形态下batch.status/batch.list_active/batch.stop对同步 batch 同样生效事件总线不可用时批处理仍能完成只是 Runner 无可见性——优雅降级。五、纵深Maintenance 安全网与陈旧任务回收Runner 的查询语义里多次出现Maintenance 会在下一轮收敛其实现位于 master 的Maintenance.handle_batch_jobs()见 salt/master.py读取batch_active.p索引对每个活跃 JID 判断age now - last_progress是否超过阈值timeout gather_job_timeout stale_buffer其中stale_buffer batch_manager_loop_interval * 6默认 5s × 6 30s。超阈值的陈旧 batch 触发salt/batch/jid/recover事件BatchManager._handle_recover()重新从磁盘读取状态、重新收养进内存活跃集合并立即强制推进一次让空余槽位尽快补发见 salt/utils/batch_manager.py。.batch.p缺失/损坏或已halted的索引条目由 Maintenance 直接清理。这解释了为什么batch.list_active可以静默丢弃坏条目而不自行修复回收是后台进程的职责Runner 只做只读快照。六、实战从 CLI 到 Runner 的完整管控闭环一个典型的多批次滚动更新场景# 1. 前台发起异步 batch示意10 台一批最多同时 10 台 salt -b 10 --batch-wait 5 web* state.apply nginx # 2. 另开终端巡检当前所有活跃 batch salt-run batch.list_active # 3. 单独盯一个批次观察 completed/pending 变化 salt-run batch.status 20240610120000000000 # 4. 发现异常先优雅排空不再发新批次 salt-run batch.stop 20240610120000000000 # 5. 若仍需立刻止血连在途任务一起终止 salt-run batch.stop 20240610120000000000 killTrue配套的 CLI 参数定义在 doc/ref/cli/salt.rst-b/--batch-size接受显式数量或百分比如10或25%--batch-wait控制每个任务完成后、槽位让出给下一个之前的等待秒数--batch-safe-limit/--batch-safe-size提供达到一定目标规模才自动转批处理的保护。批大小解析的严谨实现见salt.utils.batch_state.get_batch_size()支持10与25%两种写法空 minion 列表时返回 1 以避免调用方到处做零值防护格式非法时抛出salt.exceptions.SaltInvocationError。Runner 层的单元测试覆盖了本文全部关键行为见 tests/pytests/unit/runners/test_batch.pystatus对存在 batch 返回正确 summarytotal/pending/halted/driver字段断言对缺失 JID 返回Nonelist_active按索引列出、自动丢弃.batch.p缺失的幽灵条目、空索引返回空列表stop优雅模式断言只 fire 一次salt/batch/JID1/stop事件且reason stop缺失 JID 与已 halted 均返回False且不触碰事件总线stop(killTrue)断言cmd_async只针对active中的 minionm1、m2不含 pending 的m3、函数名为saltutil.kill_job、参数为 batch JID无在途 minion 时跳过发布但 halt 事件照常发出。集成层面tests/pytests/integration/cli/test_batch.py 还覆盖了批大小数字/百分比、grains 目标、exit code、failhard 提前终止、批量 retcode 归并等端到端行为。七、注意事项与版本背景适用前提batch.status/batch.list_active/batch.stop面向异步批处理体系含被BatchManager代管的同步 batch 可见性若某个 JID 从未以 batch 形态运行或缓存被清理status返回Nonestop返回False这是设计行为而非错误。权限与属主Runner 只读状态、只发事件不写 mastercachedir实际的.batch.p/batch_active.p写入统一由以 master 守护进程属主运行的BatchManager完成规避了 3008.2 修复的 root CLI 与 salt master 属主冲突问题。事件总线可用性所有事件操作均为 best-effort——总线不可达时批处理照常完成只是 Runner 命令失去可见性对应 salt/cli/batch.py 中的_fire_event/_subscribe_to_halt等事件胶水方法全部自吞异常。kill 的边界killTrue只针对active状态的在途 minion已入pending未下发与已done的 minion 不受影响这是先杀在途、再停调度语义的精确落点。综上salt.runners.batch是异步批处理体系的运维控制面status给你精确到每个 minion 状态的快照list_active给你全局清单stop给你从优雅排空到强制止血的完整处置能力而其背后是BatchState状态机、BatchManager事件驱动进程与 Maintenance 安全网三者构成的健壮闭环。赞分享运维配置管理后端【免费下载链接】saltSoftware to automate the management and configuration of infrastructure and applications at scale.项目地址https://gitcode.com/gh_mirrors/sa/salt点击查看免费下载相关推荐darktable 上手实践RAW 照片编辑与开源摄影工作流的完整路径darktable 上手实践RAW 照片编辑与开源摄影工作流的完整路径 相机存储卡里的一批 RAW 文件往往是摄影师最头疼的部分商业软件按年收费处理流程运维配置管理后端EasySwoole 任务管理器实战异步任务处理与性能优化EasySwoole 任务管理器实战异步任务处理与性能优化 EasySwoole 是一款基于 Swoole Server 开发的高性能 PHP 框架其内置的后端AntdUI任务处理ITask与ITaskOpacity的任务管理与异步处理AntdUI任务处理ITask与ITaskOpacity的任务管理与异步处理 在现代WinForm应用开发中流畅的用户体验和高效的异步处理是至关重要的。AnUI组件桌面应用上一篇Windows AirPlay 2投屏终极指南5步实现iOS设备无线投屏到Windows电脑下一篇CANN/opbase算子执行器预留接口创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考