"""生命周期钩子协议。 定义插件生命周期状态枚举、生命周期钩子枚举与生命周期钩子处理 Protocol。 插件通过实现 ``LifecycleHookHandler`` 响应宿主下发的状态变迁,宿主在调用 钩子时施加超时控制并在失败时触发优雅降级。 """ from __future__ import annotations from enum import StrEnum from typing import Any, Protocol, runtime_checkable class LifecycleState(StrEnum): """生命周期状态。 标识插件在生命周期中的当前状态,由宿主状态机驱动变迁。继承 ``str, Enum`` 以支持 JSON 序列化与字符串比较。 取值: DISCOVERED: 已发现(清单已加载)。 RESOLVED: 已解析(依赖已满足)。 LOADED: 已加载(模块已导入)。 INITIALIZED: 已初始化(onInit 完成)。 STARTED: 已启动(onStart 完成)。 PAUSED: 已暂停(onPause 完成)。 STOPPED: 已停止(onStop 完成)。 UNLOADED: 已卸载(onUnload 完成,资源已释放)。 FAILED: 失败(onFail 已调用,触发优雅降级)。 NOT_INSTALLED: 未安装(文件级生命周期初始态,插件文件不存在)。 INSTALLED: 已安装(插件文件已放置到插件目录,manifest 已注册, 尚未 load 进入运行时生命周期)。 """ DISCOVERED = "discovered" RESOLVED = "resolved" LOADED = "loaded" INITIALIZED = "initialized" STARTED = "started" PAUSED = "paused" STOPPED = "stopped" UNLOADED = "unloaded" FAILED = "failed" NOT_INSTALLED = "not_installed" INSTALLED = "installed" class LifecycleHook(StrEnum): """生命周期钩子。 标识宿主可调用的生命周期钩子类型,与 ``LifecycleHookHandler`` 方法 一一对应。继承 ``str, Enum`` 以支持 JSON 序列化与字符串比较。 取值: INIT: 初始化钩子(initialized 阶段)。 START: 启动钩子(started 阶段)。 STOP: 停止钩子(stopped 阶段)。 PAUSE: 暂停钩子(paused 阶段)。 RESUME: 恢复钩子(从 paused 恢复至 started)。 UNLOAD: 卸载钩子(unloaded 阶段)。 RECONFIGURE: 配置热更新钩子(FR-37)。 FAIL: 失败回调钩子(failed 阶段)。特殊性:非主动状态变迁, 由宿主在初始化 / 启动 / 运行时失败后调用(FR-32),触发 FR-36 优雅降级。``onFail`` 自身失败不得阻断降级流程。 文件级状态无钩子(FR-PLG-INSTALL): ``NOT_INSTALLED`` 与 ``INSTALLED`` 为文件级生命周期状态,由 ``PLG-INSTALL`` 端点驱动转换,**不触发** ``LifecycleHook``。 运行时生命周期从 ``LOADED`` 开始,由宿主状态机驱动并通过本枚举 对应的钩子通知插件。 """ INIT = "init" START = "start" STOP = "stop" PAUSE = "pause" RESUME = "resume" UNLOAD = "unload" RECONFIGURE = "reconfigure" FAIL = "fail" @runtime_checkable class LifecycleHookHandler(Protocol): """生命周期钩子处理 Protocol。 由插件实现,响应宿主下发的生命周期状态变迁。使用 ``@runtime_checkable`` 装饰以支持 ``isinstance`` 检查。所有钩子 均为异步方法,宿主在调用时施加超时控制。 超时配置(FR-32): - ``onInit`` / ``onStart``:默认 60s。 - ``onPause`` / ``onResume`` / ``onStop`` / ``onUnload``:默认 30s。 - 超时后宿主标记插件为 ``FAILED`` 状态并触发 FR-36 优雅降级。 资源释放约束(FR-32): - 插件卸载时(``onUnload``)**必须** 释放所有资源(关闭连接、 清理缓存、取消订阅),**不得** 留下孤儿资源。 - 插件停止时(``onStop``)**必须** 等待在途请求完成(默认超时 30s),超时后强制中止并记录告警日志。 - ``onReconfigure`` 用于配置热更新(FR-37),**必须** 支持配置回滚。 """ async def onInit(self) -> None: """初始化钩子,在 initialized 阶段调用。 超时 60s,超时后标记插件失败。 @consistency: 状态机驱动(state-machine),钩子完成后状态机推进至 INITIALIZED。 @idempotent: False — 初始化可能涉及资源分配与订阅建立,重复执行有副作用。 """ ... async def onStart(self) -> None: """启动钩子,在 started 阶段调用。 超时 60s,超时后标记插件失败。 @consistency: 状态机驱动(state-machine),钩子完成后状态机推进至 STARTED。 @idempotent: False — 启动涉及连接建立与事件订阅,重复执行有副作用。 """ ... async def onStop(self) -> None: """停止钩子,在 stopped 阶段调用。 超时 30s,必须等待在途请求完成。 @consistency: 状态机驱动(state-machine),钩子完成后状态机推进至 STOPPED。 @idempotent: True — 停止已停止的插件应安全,重复调用仅产生等价的已停止状态。 """ ... async def onPause(self) -> None: """暂停钩子,在 paused 阶段调用。 超时 30s。 @consistency: 状态机驱动(state-machine),钩子完成后状态机推进至 PAUSED。 @idempotent: True — 暂停已暂停的插件应安全,重复调用仅产生等价的已暂停状态。 """ ... async def onResume(self) -> None: """恢复钩子,从 paused 恢复到 started。 超时 30s。 @consistency: 状态机驱动(state-machine),钩子完成后状态机推进至 STARTED。 @idempotent: False — 恢复涉及重新激活订阅与连接,重复执行有副作用。 """ ... async def onUnload(self) -> None: """卸载钩子,在 unloaded 阶段调用。 超时 30s,必须释放所有资源,不得留下孤儿资源。 @consistency: 状态机驱动(state-machine),钩子完成后状态机推进至 UNLOADED。 @idempotent: True — 卸载已卸载的插件应安全,重复调用仅清理已释放的资源。 """ ... async def onReconfigure( self, *, old_config: dict[str, Any] | None = None, new_config: dict[str, Any], ) -> None: """配置热更新钩子(FR-37)。 参数: old_config: 上一次的有效配置字典,由宿主在调用时通过关键字参数 传入;首次调用或无基线时为 ``None``。插件可据此做差异化校验, 无需自行维护基线缓存。 new_config: 新配置字典,必须支持回滚。 迁移说明:本 Protocol 声明 ``old_config`` 形参。旧插件升级时应补充 ``old_config`` 形参以接收旧配置;若旧插件实现 ``async def onReconfigure(self, *, new_config)``(无 ``old_config``), 宿主调用时传 ``old_config=...`` 会触发 ``TypeError``。宿主实现侧如需 兼容此类旧插件,可通过 ``inspect`` 检查方法签名决定是否传 ``old_config`` (如 ``inspect.signature`` 检测是否含 ``old_config`` 形参)。 @consistency: 状态机驱动(state-machine),配置变更即时生效且必须支持回滚。 @idempotent: True — 相同配置字典重复应用应产生等价结果,无累积副作用。 """ ... async def onFail(self, error: str) -> None: """插件失败钩子(FR-32)。 插件初始化/启动/运行时失败时调用,用于清理资源、记录状态。 宿主调用此钩子后标记插件为 ``FAILED`` 状态并触发 FR-36 优雅降级。 参数: error: 错误描述。 @consistency: 状态机驱动(state-machine),钩子完成后状态机推进至 FAILED 并触发降级;钩子失败不阻断降级。 @idempotent: True — 重复通知失败应安全,仅记录状态与清理资源,无累积副作用。 """ ...