modify: worker 管理多进程副本
This commit is contained in:
@@ -43,7 +43,7 @@ def load_plugin_config(worker_type: str, config_dir: str = "config/workers") ->
|
||||
|
||||
Returns:
|
||||
{"type", "module", "factory", "cleanup", "count", "load_mode",
|
||||
"mqtt_topics", "config": 展平后的运行时配置}
|
||||
"mqtt_topics", "cache"([workers.cache] 段), "config": 展平后的运行时配置}
|
||||
"""
|
||||
import pathlib
|
||||
|
||||
@@ -67,7 +67,7 @@ def load_plugin_config(worker_type: str, config_dir: str = "config/workers") ->
|
||||
mqtt_topics.append(t)
|
||||
|
||||
workers_flat = {k: v for k, v in workers_section.items()
|
||||
if k not in ("config", "mqtt_topics", "load_mode")}
|
||||
if k not in ("config", "mqtt_topics", "load_mode", "cache")}
|
||||
runtime_config = {
|
||||
**plugin_conf,
|
||||
**workers_flat,
|
||||
@@ -82,10 +82,24 @@ def load_plugin_config(worker_type: str, config_dir: str = "config/workers") ->
|
||||
"count": workers_section.get("count", 1),
|
||||
"load_mode": load_mode,
|
||||
"mqtt_topics": mqtt_topics,
|
||||
"cache": dict(workers_section.get("cache") or {}),
|
||||
"config": runtime_config,
|
||||
}
|
||||
|
||||
|
||||
def build_worker_cache(cache_cfg: dict):
|
||||
"""按插件 [workers.cache] 段建立配置缓存(redis/diskcache),返回 (cache, mode)。
|
||||
|
||||
从配置中剔除内部控制键 launch_worker_count(决定配置优先来源 toml/cache),
|
||||
避免其被当作后端连接参数传给 Cache.from_config。
|
||||
"""
|
||||
from chongming_cache import Cache
|
||||
|
||||
mode = str((cache_cfg or {}).get("launch_worker_count", "toml")).lower()
|
||||
clean = {k: v for k, v in (cache_cfg or {}).items() if k != "launch_worker_count"}
|
||||
return Cache.from_config(clean), mode
|
||||
|
||||
|
||||
def worker_serve():
|
||||
"""独立 Worker 进程入口(console script: chongming-worker / worker_serve)。"""
|
||||
# 独立进程不依赖网关的日志配置,兜底 basicConfig(已有 handler 时不覆盖)
|
||||
@@ -99,6 +113,12 @@ def worker_serve():
|
||||
parser.add_argument("--type", required=True, help="插件类型(如 demo / example)")
|
||||
parser.add_argument("--count", type=int, default=None, help="副本数(覆盖配置中的 count)")
|
||||
parser.add_argument("--config", default="config.toml", help="全局配置文件路径(读取 [zenoh] 节)")
|
||||
parser.add_argument(
|
||||
"--instance", default=None,
|
||||
help="外部进程实例标识(多实例全局分摊/逐实例精细扩缩用)。缺省用 "
|
||||
"CHONGMING_WORKER_INSTANCE 或 {hostname}:{pid}(同机多实例默认即自动区分);"
|
||||
"跨重启稳定适逐实例缩放请显式指定",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# console script 启动时 sys.path 不含当前目录,显式加入以保证
|
||||
@@ -136,6 +156,36 @@ def worker_serve():
|
||||
session = zenoh.open(zconfig)
|
||||
logger.info("[%s] Zenoh 会话已建立", args.type)
|
||||
|
||||
# 1.5 配置缓存([workers.cache] 段,进程插件自行管理)+ 配置优先来源登记
|
||||
# [workers.config] 的单一事实来源解析由 worker 运行时(create_workers)统一完成。
|
||||
# 多实例场景下还登记「外部进程实例参与方」,使扩缩容按存活实例数分摊全局 count。
|
||||
from chongming_worker.runtime import (
|
||||
register_instance,
|
||||
run_instance_heartbeat,
|
||||
set_current_instance_id,
|
||||
set_worker_cache,
|
||||
set_worker_mode,
|
||||
unregister_instance,
|
||||
)
|
||||
set_current_instance_id(args.instance)
|
||||
|
||||
cache = None
|
||||
mode = "toml"
|
||||
hb_task = None # 实例参与方心跳任务(外部多实例全局分摊用)
|
||||
if wc.get("cache"):
|
||||
cache, mode = build_worker_cache(wc["cache"])
|
||||
set_worker_cache(args.type, cache)
|
||||
set_worker_mode(args.type, mode)
|
||||
register_instance(args.type, cache, args.instance)
|
||||
hb_task = asyncio.create_task(
|
||||
run_instance_heartbeat(args.type, cache, instance_id=args.instance)
|
||||
)
|
||||
logger.info(
|
||||
"[%s] 已启用配置缓存(backend=%s, mode=%s)并登记外部实例参与方",
|
||||
args.type, getattr(getattr(cache, "backend", None), "name", "?"), mode,
|
||||
)
|
||||
worker_config = wc["config"]
|
||||
|
||||
try:
|
||||
# 2. import 插件(触发 @rpc_method 注册),然后契约校验
|
||||
module = __import__(wc["module"], fromlist=[wc["factory"]])
|
||||
@@ -145,9 +195,9 @@ def worker_serve():
|
||||
factory = getattr(module, wc["factory"])
|
||||
count = args.count or wc.get("count", 1)
|
||||
if inspect.iscoroutinefunction(factory):
|
||||
tasks = await factory(session, wc["config"], count, worker_manager=None)
|
||||
tasks = await factory(session, worker_config, count, worker_manager=None)
|
||||
else:
|
||||
tasks = factory(session, wc["config"], count, worker_manager=None)
|
||||
tasks = factory(session, worker_config, count, worker_manager=None)
|
||||
|
||||
# 4. 发布路由描述符(网关 RouteRegistry 订阅后动态挂载 HTTP 路由)
|
||||
publisher = RoutePublisher(session, args.type)
|
||||
@@ -173,6 +223,9 @@ def worker_serve():
|
||||
await stop_event.wait()
|
||||
announce_task.cancel()
|
||||
await asyncio.gather(announce_task, return_exceptions=True)
|
||||
if hb_task is not None:
|
||||
hb_task.cancel()
|
||||
await asyncio.gather(hb_task, return_exceptions=True)
|
||||
|
||||
# 6. 优雅退出:摘除路由 → cleanup → 取消副本任务 → 关闭会话
|
||||
publisher.unpublish()
|
||||
@@ -187,9 +240,16 @@ def worker_serve():
|
||||
t.cancel()
|
||||
if tasks:
|
||||
await asyncio.gather(*tasks, return_exceptions=True)
|
||||
if cache is not None:
|
||||
unregister_instance(args.type, cache, args.instance)
|
||||
logger.info("[%s] Worker 进程已退出", args.type)
|
||||
finally:
|
||||
session.close()
|
||||
if cache is not None:
|
||||
try:
|
||||
cache.close()
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
|
||||
try:
|
||||
asyncio.run(_run())
|
||||
|
||||
Reference in New Issue
Block a user