外部系统集成模式
本文总结 BPMAX 插件最常见的外部系统集成模式,帮助开发者按问题类型选择合适的插件设计方案。
学习目标
- 理解常见企业插件集成模式
- 学会为不同类型的外部系统设计插件结构
- 理解鉴权、回调、缓存、重试和队列的组合方式
模式一:自定义鉴权插件
适用场景
适合平台已有统一调用链,但第三方要求特殊鉴权方式的场景。
注册时机
通常在插件启动时完成注册,使后续调用链能直接复用。
Token 获取与缓存
鉴权插件应优先考虑:
- token 获取逻辑封装
- 缓存过期时间
- 提前刷新策略
一个最小服务示例如下:
export default class PluginAuthService extends think.Service {
async getAccessToken(config) {
const cacheKey = `plugin_auth:${config.app_id}`;
const cached = await this.redis.get(cacheKey);
if (cached) {
return cached;
}
const res = await this.http.post('/oauth/token', {
app_id: config.app_id,
secret: config.secret,
});
const token = res.data.access_token;
await this.redis.set(cacheKey, token, 'EX', 7000);
return token;
}
}失败处理
鉴权失败通常不是“多试几次就好”。需要区分:
- 临时网络失败
- 配置错误
- 凭证失效
调用侧可以这样区分错误:
try {
const token = await this.service('plugin_auth').getAccessToken(config);
return token;
} catch (error) {
think.logger.error('[plugin_auth] get token failed', error);
throw error;
}模式二:任务/消息协同插件
适用场景
适合把流程事件同步成外部任务、消息或通知对象。
流程配置与任务映射
这类插件通常需要:
- 在流程或环节中收集配置
- 把平台数据映射成第三方字段
- 设计任务创建与更新规则
任务映射函数可以单独维护:
function buildTaskPayload(project, config) {
return {
title: project.name,
description: project.remark || '',
owner_id: config.owner_id,
source_id: project.guid,
};
}状态回写设计
如果第三方对象有生命周期,建议同时考虑:
- 创建
- 更新
- 完成
- 失败补偿
状态回写服务可以先定义成:
async syncTaskStatus(taskId, status, config) {
const token = await this.service('plugin_auth').getAccessToken(config);
return this.http.patch(
`/tasks/${taskId}`,
{ status },
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
}模式三:组织架构同步插件
适用场景
适合平台组织、团队、用户等对象要与第三方系统保持同步的场景。
事件驱动与全量刷新结合
只靠事件驱动通常不够,建议同时保留:
- 增量同步
- 手工全量刷新
- 异常补偿
例如可以保留两个入口:
async syncDepartmentEvent(payload) {
return this.service('plugin_org_sync').syncSingle(payload);
}
async syncAllDepartments() {
return this.service('plugin_org_sync').syncAll();
}模型映射与唯一标识设计
这类插件最重要的是唯一标识设计。必须先明确:
- 平台和第三方的对应主键是什么
- 用户和团队的绑定规则是什么
模式四:资源与指标上报插件
适用场景
适合把调用量、资源消耗、对象数量等数据定期上报到外部平台。
队列缓存
为了降低上报链路耦合,建议先本地收集,再异步上报。
例如:
await this.redis.lpush(
'plugin_metrics:queue',
JSON.stringify({
metric: 'task_count',
value: 12,
created_at: Date.now(),
})
);批量上报
批量策略需要平衡:
- 实时性
- 请求次数
- 失败影响范围
批量发送可以先写成:
async reportMetricsBatch() {
const items = await this.redis.lrange('plugin_metrics:queue', 0, 99);
if (!items.length) return;
const payload = items.map(item => JSON.parse(item));
await this.http.post('/metrics/batch', payload);
}重试与监控
这类插件通常必须具备:
- 失败重试
- 状态统计
- 队列清理
通用设计要点
配置隔离
每个外部系统集成都应有独立配置,避免多个能力共用一份难以维护的大配置。
凭证管理
不要把凭证散落在页面逻辑里,尽量统一交给后端服务层处理。
幂等与重试
只要涉及网络调用和异步任务,就要同时考虑幂等和重试,不能只做其一。
日志与可观测性
至少应能回答:
- 调用了哪个外部接口
- 用了哪组配置
- 成功还是失败
- 失败原因是什么
