开发插件服务
实现生命周期插件 Endpoint,处理可重试 Hook、属性输出、服务身份和外部资源隔离。
插件服务是拥有外部资源操作逻辑的独立后端。平台只负责解析注册记录、校验 Hook、合并配置并调用 Endpoint;外部租户、许可证、数据库或其他资源的真实状态仍归插件服务及其上游系统所有。
1. 定义稳定 Endpoint
插件至少提供一个接收 JSON POST 的执行 Endpoint。它必须:
- 接受当前协议 v1 的完整请求对象。
- 同时接受同值的
hook和stage,业务逻辑以hook为准。 - 返回完整 CModel envelope,成功时包含
data.status和data.properties。 - 在重试、超时重发和服务重启后保持同一资源身份。
- 不接受请求体中的工作区或用户字段作为 Endpoint 凭据。
executeUrl 在注册时保存为完整 URL。不要让管理服务根据 executorType、插件名称或某个环境的
主机和端口拼接地址。部署地址变更时更新注册记录,不在插件协议中增加环境分支。
2. 把 Hook 实现为状态收敛
v1 没有独立幂等键,插件不能假设 Hook 只会调用一次。每次执行应先读取当前外部状态,再将其收敛到目标:
解析 Runtime + service + 已保存的外部引用
-> 查询外部资源当前状态
-> 已符合目标:直接返回当前结果
-> 不符合目标:执行必要变更
-> 重新查询并返回最终结果例如,BEFORE_DEPLOY 收到已有外部实例引用时,先查询并复用该实例;不能每次都创建新租户。
BEFORE_DETACH 只收敛“当前 Runtime 不再绑定”,不能默认删除可能被其他绑定复用的外部资源。
3. 使用明确的外部资源引用
需要在后续 Hook 复用的外部实例身份,必须返回到已声明且允许写回的模块属性。例如:
{
"errorCode": "0",
"value": "success",
"systemCurrentTime": 1786665600000,
"data": {
"status": "RUNNING",
"properties": {
"externalInstanceRef": {
"@type": "Data",
"value": "external-instance-reference"
}
}
}
}插件只返回自己拥有且当前 Hook 确实生成的输出。不得返回未在 propertyDefinitions 声明的属性,
不得使用输出覆盖用户拥有的普通配置,也不得直接修改模块安装记录或 Runtime 状态。
4. 分离配置和凭据
pluginConfig 用于非敏感的执行策略和资源引用,例如需要同步的属性名列表。它不是密钥容器。
- 访问上游系统的凭据由插件服务自己的受控配置管理。
- 不在
defaultConfig、pluginConfig、属性输出、URL 或错误信息中携带凭据。 - 日志只记录稳定资源引用、Hook、结果和可追踪错误,不记录完整请求或属性密文。
- 插件返回的
value不得包含 token、密码或上游响应原文。
5. 区分平台身份与外部主键
applicationRuntimeId 和 serviceId 用于定位本次平台绑定,不应直接成为对外展示的业务主键。
外部系统产生的实例编号应作为独立引用保存,并在后续 Hook 中继续使用。不同 Runtime 的安装不得
因为插件默认值、缓存键或全局单例而共享同一组可变凭据或错误覆盖对方资源。
6. 失败要求
- 请求字段或外部状态不符合执行条件时,返回非
"0"的errorCode和稳定错误信息。 - 不能处理的 Hook 不应注册到
supportedHooks,不得收到后静默成功。 - 上游超时或状态不确定时,不得伪造成功结果或创建第二个资源规避查询。
- 插件不可用时,让当前 Runtime 操作明确失败,不设计“跳过插件也算成功”的私有兼容分支。