"""Worker 并发上限:配置解析与认领判断(纯函数,无 DB、无 IO)。 配置来源与优先级(高到低): 1. 显式值:Worker 构造参数 capacity / CLI --worker-capacity。 2. 环境变量 CLOUD_WORKER_CAPACITY(CLI 未给时生效)。 3. 默认值 1:默认行为不得弱于现状,即旧串行行为。 非法值(非整数、<= 0)一律归一化为 1,绝不出现 0 上限导致 worker 永远认领不到任务,也绝不出现负数上限。 workers 表的 capacity 是注册表展示值,不是控制面下推: 本地 worker 只执行自己启动时的配置,表里被改大的值不会 悄悄抬高本 worker 的上限(否则 stale 行或误写会放大并发)。 上限口径(单 worker 本地计数): - running 数 = Worker._running 的条目数(_running_lock 下读)。 - 启动中的任务也算:_claim 占位时就先在 _running 里建空条目, 执行器起 proc / 容器后 _running_set 只往该条目里补字段, 不新增条目;所以“已认领未起进程”与“已起进程”都占一个槽。 - 同一任务重复占位不重复计数(dict 按 task_id 去重)。 - 本模块只管单 worker 上限;多 worker 全局上限不在此列, 见汇报里的诚实边界(项目级上限同样是遗留项)。 """ import os DEFAULT_CAPACITY = 1 ENV_VAR = "CLOUD_WORKER_CAPACITY" def parse_capacity(value): """把任意输入归一化为 >= 1 的整数上限;非法值返回 1。""" try: capacity = int(value) except (TypeError, ValueError): return DEFAULT_CAPACITY if capacity < 1: return DEFAULT_CAPACITY return capacity def resolve_capacity(explicit=None, env=None): """按“显式 > 环境变量 > 默认 1”解析上限。 explicit 为 None 表示调用方未给(CLI 未传 --worker-capacity 时 argparse 默认即 None);env 默认读进程环境,单测可注入 普通 dict。显式值即使非法也按非法处理(归一为 1),不回落 到环境变量:显式给错了就该按 1 跑,而不是悄悄用环境值。 """ if explicit is not None: return parse_capacity(explicit) source = env if env is not None else os.environ try: raw = source.get(ENV_VAR) except Exception: raw = None if raw is None or (isinstance(raw, str) and not raw.strip()): return DEFAULT_CAPACITY return parse_capacity(raw) def effective_capacity(capacity): """运行期上限:构造后 self.capacity 可能来自旧调用方,统一归一。""" return parse_capacity(capacity) def running_count(running_snapshot): """_running 快照的条目数:空条目(启动中)同样计数。""" try: return len(running_snapshot) except TypeError: return 0 def can_claim(running_count_value, capacity): """未满返回 True;running 数达到上限时不再认领。""" return running_count_value < effective_capacity(capacity)