本次提交包含多维度代码优化与功能增强: 1. 移除报告模块冗余导入与枚举,清理报表相关代码 2. 新增扫码登录支持方法与飞书适配器适配 3. 完善异常日志与健康检查信息 4. 扩展目录、配对管理、能力查询等接口 5. 优化出站管道与事务提交后钩子逻辑 6. 修复飞书消息解析与响应空值问题 7. 重构配置更新与服务账号创建逻辑 8. 统一传输错误分类契约与错误基类扩展
203 lines
8.2 KiB
Python
203 lines
8.2 KiB
Python
"""生命周期钩子协议。
|
||
|
||
定义插件生命周期状态枚举、生命周期钩子枚举与生命周期钩子处理 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 — 重复通知失败应安全,仅记录状态与清理资源,无累积副作用。
|
||
"""
|
||
...
|