feat: 添加货币和汇率管理功能
refactor: 重构前端路由和登录逻辑 docs: 更新业务闭环、任务和架构文档 style: 调整代码格式和文件结构 chore: 更新依赖项和配置文件
This commit is contained in:
457
server/src/core/data/DataGovernance.ts
Normal file
457
server/src/core/data/DataGovernance.ts
Normal file
@@ -0,0 +1,457 @@
|
||||
import { DomainEventBus } from '../runtime/DomainEventBus';
|
||||
|
||||
// 数据分类
|
||||
export interface DataClassification {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
sensitivity: 'public' | 'internal' | 'confidential' | 'restricted';
|
||||
retentionPeriod: number; // 天数
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
}
|
||||
|
||||
// 数据访问策略
|
||||
export interface DataAccessPolicy {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
classificationId: string;
|
||||
roles: string[];
|
||||
permissions: 'read' | 'write' | 'delete' | 'admin';
|
||||
conditions?: string; // 访问条件
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
}
|
||||
|
||||
// 数据审计日志
|
||||
export interface DataAuditLog {
|
||||
id: string;
|
||||
userId: string;
|
||||
action: 'read' | 'write' | 'delete' | 'access' | 'export';
|
||||
dataClassification: string;
|
||||
dataEntity: string;
|
||||
recordId?: string;
|
||||
ipAddress: string;
|
||||
timestamp: Date;
|
||||
status: 'success' | 'failed';
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
// 数据隐私设置
|
||||
export interface DataPrivacySetting {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
type: 'anonymization' | 'masking' | 'encryption' | 'retention';
|
||||
configuration: Record<string, any>;
|
||||
enabled: boolean;
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
}
|
||||
|
||||
// 数据治理
|
||||
export class DataGovernance {
|
||||
private static instance: DataGovernance;
|
||||
private dataClassifications: Map<string, DataClassification> = new Map();
|
||||
private accessPolicies: Map<string, DataAccessPolicy> = new Map();
|
||||
private auditLogs: Map<string, DataAuditLog> = new Map();
|
||||
private privacySettings: Map<string, DataPrivacySetting> = new Map();
|
||||
private eventBus: DomainEventBus;
|
||||
|
||||
private constructor() {
|
||||
this.eventBus = DomainEventBus.getInstance();
|
||||
}
|
||||
|
||||
static getInstance(): DataGovernance {
|
||||
if (!DataGovernance.instance) {
|
||||
DataGovernance.instance = new DataGovernance();
|
||||
}
|
||||
return DataGovernance.instance;
|
||||
}
|
||||
|
||||
// 创建数据分类
|
||||
async createDataClassification(classification: Omit<DataClassification, 'id' | 'createdAt' | 'lastUpdated'>): Promise<DataClassification> {
|
||||
const id = `class_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newClassification: DataClassification = {
|
||||
...classification,
|
||||
id,
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.dataClassifications.set(id, newClassification);
|
||||
this.eventBus.publish('data.classification.created', newClassification);
|
||||
return newClassification;
|
||||
}
|
||||
|
||||
// 获取数据分类
|
||||
getDataClassification(classificationId: string): DataClassification | undefined {
|
||||
return this.dataClassifications.get(classificationId);
|
||||
}
|
||||
|
||||
// 获取所有数据分类
|
||||
getAllDataClassifications(): DataClassification[] {
|
||||
return Array.from(this.dataClassifications.values());
|
||||
}
|
||||
|
||||
// 更新数据分类
|
||||
async updateDataClassification(classificationId: string, updates: Partial<DataClassification>): Promise<DataClassification | null> {
|
||||
const classification = this.dataClassifications.get(classificationId);
|
||||
if (!classification) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedClassification = {
|
||||
...classification,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.dataClassifications.set(classificationId, updatedClassification);
|
||||
this.eventBus.publish('data.classification.updated', updatedClassification);
|
||||
return updatedClassification;
|
||||
}
|
||||
|
||||
// 创建数据访问策略
|
||||
async createAccessPolicy(policy: Omit<DataAccessPolicy, 'id' | 'createdAt' | 'lastUpdated'>): Promise<DataAccessPolicy> {
|
||||
const id = `policy_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newPolicy: DataAccessPolicy = {
|
||||
...policy,
|
||||
id,
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.accessPolicies.set(id, newPolicy);
|
||||
this.eventBus.publish('data.access.policy.created', newPolicy);
|
||||
return newPolicy;
|
||||
}
|
||||
|
||||
// 获取数据访问策略
|
||||
getAccessPolicy(policyId: string): DataAccessPolicy | undefined {
|
||||
return this.accessPolicies.get(policyId);
|
||||
}
|
||||
|
||||
// 获取所有数据访问策略
|
||||
getAllAccessPolicies(filters?: {
|
||||
classificationId?: string;
|
||||
role?: string;
|
||||
permissions?: string;
|
||||
}): DataAccessPolicy[] {
|
||||
let result = Array.from(this.accessPolicies.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.classificationId) {
|
||||
result = result.filter(p => p.classificationId === filters.classificationId);
|
||||
}
|
||||
|
||||
if (filters.role) {
|
||||
result = result.filter(p => p.roles.includes(filters.role!));
|
||||
}
|
||||
|
||||
if (filters.permissions) {
|
||||
result = result.filter(p => p.permissions === filters.permissions);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 更新数据访问策略
|
||||
async updateAccessPolicy(policyId: string, updates: Partial<DataAccessPolicy>): Promise<DataAccessPolicy | null> {
|
||||
const policy = this.accessPolicies.get(policyId);
|
||||
if (!policy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedPolicy = {
|
||||
...policy,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.accessPolicies.set(policyId, updatedPolicy);
|
||||
this.eventBus.publish('data.access.policy.updated', updatedPolicy);
|
||||
return updatedPolicy;
|
||||
}
|
||||
|
||||
// 检查数据访问权限
|
||||
async checkAccessPermission(userId: string, role: string, dataClassification: string, action: 'read' | 'write' | 'delete' | 'admin'): Promise<{
|
||||
allowed: boolean;
|
||||
policyId?: string;
|
||||
reason?: string;
|
||||
}> {
|
||||
// 这里应该有实际的权限检查逻辑
|
||||
// 暂时模拟检查
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
const policies = Array.from(this.accessPolicies.values()).filter(
|
||||
p => p.classificationId === dataClassification && p.roles.includes(role)
|
||||
);
|
||||
|
||||
if (policies.length === 0) {
|
||||
return { allowed: false, reason: 'No policy found for this role and classification' };
|
||||
}
|
||||
|
||||
const policy = policies.find(p => {
|
||||
switch (action) {
|
||||
case 'admin':
|
||||
return p.permissions === 'admin';
|
||||
case 'delete':
|
||||
return p.permissions === 'admin' || p.permissions === 'delete';
|
||||
case 'write':
|
||||
return p.permissions === 'admin' || p.permissions === 'delete' || p.permissions === 'write';
|
||||
case 'read':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (policy) {
|
||||
return { allowed: true, policyId: policy.id };
|
||||
} else {
|
||||
return { allowed: false, reason: 'Insufficient permissions' };
|
||||
}
|
||||
}
|
||||
|
||||
// 记录数据审计日志
|
||||
async logAuditEvent(log: Omit<DataAuditLog, 'id' | 'timestamp'>): Promise<DataAuditLog> {
|
||||
const id = `log_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newLog: DataAuditLog = {
|
||||
...log,
|
||||
id,
|
||||
timestamp: new Date()
|
||||
};
|
||||
|
||||
this.auditLogs.set(id, newLog);
|
||||
this.eventBus.publish('data.audit.log.created', newLog);
|
||||
return newLog;
|
||||
}
|
||||
|
||||
// 获取审计日志
|
||||
getAuditLog(logId: string): DataAuditLog | undefined {
|
||||
return this.auditLogs.get(logId);
|
||||
}
|
||||
|
||||
// 获取审计日志
|
||||
getAuditLogs(filters?: {
|
||||
userId?: string;
|
||||
action?: string;
|
||||
dataClassification?: string;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
}): DataAuditLog[] {
|
||||
let result = Array.from(this.auditLogs.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.userId) {
|
||||
result = result.filter(l => l.userId === filters.userId);
|
||||
}
|
||||
|
||||
if (filters.action) {
|
||||
result = result.filter(l => l.action === filters.action);
|
||||
}
|
||||
|
||||
if (filters.dataClassification) {
|
||||
result = result.filter(l => l.dataClassification === filters.dataClassification);
|
||||
}
|
||||
|
||||
if (filters.startDate) {
|
||||
result = result.filter(l => l.timestamp >= filters.startDate!);
|
||||
}
|
||||
|
||||
if (filters.endDate) {
|
||||
result = result.filter(l => l.timestamp <= filters.endDate!);
|
||||
}
|
||||
}
|
||||
|
||||
return result.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
||||
}
|
||||
|
||||
// 创建数据隐私设置
|
||||
async createPrivacySetting(setting: Omit<DataPrivacySetting, 'id' | 'createdAt' | 'lastUpdated'>): Promise<DataPrivacySetting> {
|
||||
const id = `privacy_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newSetting: DataPrivacySetting = {
|
||||
...setting,
|
||||
id,
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.privacySettings.set(id, newSetting);
|
||||
this.eventBus.publish('data.privacy.setting.created', newSetting);
|
||||
return newSetting;
|
||||
}
|
||||
|
||||
// 获取数据隐私设置
|
||||
getPrivacySetting(settingId: string): DataPrivacySetting | undefined {
|
||||
return this.privacySettings.get(settingId);
|
||||
}
|
||||
|
||||
// 获取所有数据隐私设置
|
||||
getAllPrivacySettings(filters?: {
|
||||
type?: string;
|
||||
enabled?: boolean;
|
||||
}): DataPrivacySetting[] {
|
||||
let result = Array.from(this.privacySettings.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.type) {
|
||||
result = result.filter(s => s.type === filters.type);
|
||||
}
|
||||
|
||||
if (filters.enabled !== undefined) {
|
||||
result = result.filter(s => s.enabled === filters.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 更新数据隐私设置
|
||||
async updatePrivacySetting(settingId: string, updates: Partial<DataPrivacySetting>): Promise<DataPrivacySetting | null> {
|
||||
const setting = this.privacySettings.get(settingId);
|
||||
if (!setting) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedSetting = {
|
||||
...setting,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.privacySettings.set(settingId, updatedSetting);
|
||||
this.eventBus.publish('data.privacy.setting.updated', updatedSetting);
|
||||
return updatedSetting;
|
||||
}
|
||||
|
||||
// 启用/禁用数据隐私设置
|
||||
async togglePrivacySetting(settingId: string, enabled: boolean): Promise<boolean> {
|
||||
const setting = this.privacySettings.get(settingId);
|
||||
if (!setting) {
|
||||
return false;
|
||||
}
|
||||
|
||||
setting.enabled = enabled;
|
||||
setting.lastUpdated = new Date();
|
||||
this.privacySettings.set(settingId, setting);
|
||||
this.eventBus.publish('data.privacy.setting.toggled', setting);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 应用数据隐私处理
|
||||
async applyPrivacyTreatment(data: any, classificationId: string): Promise<any> {
|
||||
// 这里应该有实际的隐私处理逻辑
|
||||
// 暂时模拟处理
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
|
||||
const classification = this.dataClassifications.get(classificationId);
|
||||
if (!classification) {
|
||||
return data;
|
||||
}
|
||||
|
||||
// 根据数据分类应用不同的隐私处理
|
||||
switch (classification.sensitivity) {
|
||||
case 'restricted':
|
||||
// 应用最严格的隐私处理
|
||||
return this.maskSensitiveData(data);
|
||||
case 'confidential':
|
||||
// 应用中等隐私处理
|
||||
return this.anonymizeData(data);
|
||||
case 'internal':
|
||||
// 应用轻度隐私处理
|
||||
return this.removePII(data);
|
||||
case 'public':
|
||||
default:
|
||||
// 无需处理
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
// 掩码敏感数据
|
||||
private maskSensitiveData(data: any): any {
|
||||
// 这里应该有实际的掩码逻辑
|
||||
return { ...data, masked: true };
|
||||
}
|
||||
|
||||
// 匿名化数据
|
||||
private anonymizeData(data: any): any {
|
||||
// 这里应该有实际的匿名化逻辑
|
||||
return { ...data, anonymized: true };
|
||||
}
|
||||
|
||||
// 移除个人身份信息
|
||||
private removePII(data: any): any {
|
||||
// 这里应该有实际的PII移除逻辑
|
||||
return { ...data, piiRemoved: true };
|
||||
}
|
||||
|
||||
// 生成数据治理报告
|
||||
async generateGovernanceReport(): Promise<{
|
||||
summary: {
|
||||
totalClassifications: number;
|
||||
totalPolicies: number;
|
||||
totalAuditLogs: number;
|
||||
totalPrivacySettings: number;
|
||||
};
|
||||
classifications: DataClassification[];
|
||||
policies: DataAccessPolicy[];
|
||||
recentAuditLogs: DataAuditLog[];
|
||||
privacySettings: DataPrivacySetting[];
|
||||
}> {
|
||||
const classifications = Array.from(this.dataClassifications.values());
|
||||
const policies = Array.from(this.accessPolicies.values());
|
||||
const auditLogs = Array.from(this.auditLogs.values()).sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()).slice(0, 100);
|
||||
const privacySettings = Array.from(this.privacySettings.values());
|
||||
|
||||
return {
|
||||
summary: {
|
||||
totalClassifications: classifications.length,
|
||||
totalPolicies: policies.length,
|
||||
totalAuditLogs: this.auditLogs.size,
|
||||
totalPrivacySettings: privacySettings.length
|
||||
},
|
||||
classifications,
|
||||
policies,
|
||||
recentAuditLogs: auditLogs,
|
||||
privacySettings
|
||||
};
|
||||
}
|
||||
|
||||
// 获取数据治理统计信息
|
||||
getGovernanceStats(): {
|
||||
totalClassifications: number;
|
||||
totalPolicies: number;
|
||||
totalAuditLogs: number;
|
||||
totalPrivacySettings: number;
|
||||
enabledPrivacySettings: number;
|
||||
auditLogsToday: number;
|
||||
} {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
const auditLogsToday = Array.from(this.auditLogs.values())
|
||||
.filter(log => log.timestamp >= today)
|
||||
.length;
|
||||
|
||||
const enabledPrivacySettings = Array.from(this.privacySettings.values())
|
||||
.filter(setting => setting.enabled)
|
||||
.length;
|
||||
|
||||
return {
|
||||
totalClassifications: this.dataClassifications.size,
|
||||
totalPolicies: this.accessPolicies.size,
|
||||
totalAuditLogs: this.auditLogs.size,
|
||||
totalPrivacySettings: this.privacySettings.size,
|
||||
enabledPrivacySettings,
|
||||
auditLogsToday
|
||||
};
|
||||
}
|
||||
}
|
||||
392
server/src/core/data/DataIntegrationPlatform.ts
Normal file
392
server/src/core/data/DataIntegrationPlatform.ts
Normal file
@@ -0,0 +1,392 @@
|
||||
import { DomainEventBus } from '../runtime/DomainEventBus';
|
||||
|
||||
// 数据源配置
|
||||
export interface DataSourceConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
type: 'database' | 'api' | 'file' | 'stream';
|
||||
connectionString: string;
|
||||
credentials?: Record<string, string>;
|
||||
options?: Record<string, any>;
|
||||
status: 'active' | 'inactive' | 'error';
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
}
|
||||
|
||||
// 数据转换规则
|
||||
export interface DataTransformationRule {
|
||||
id: string;
|
||||
name: string;
|
||||
sourceField: string;
|
||||
targetField: string;
|
||||
transformation: string; // 转换表达式
|
||||
conditions?: string; // 条件表达式
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
}
|
||||
|
||||
// 数据集成任务
|
||||
export interface IntegrationTask {
|
||||
id: string;
|
||||
name: string;
|
||||
sourceDataSourceId: string;
|
||||
targetDataSourceId: string;
|
||||
transformationRules: string[]; // 规则ID列表
|
||||
schedule: string; // cron表达式
|
||||
status: 'pending' | 'running' | 'success' | 'failed';
|
||||
lastRun: Date | null;
|
||||
nextRun: Date | null;
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
}
|
||||
|
||||
// 集成任务执行日志
|
||||
export interface IntegrationLog {
|
||||
id: string;
|
||||
taskId: string;
|
||||
status: 'success' | 'failed';
|
||||
startTime: Date;
|
||||
endTime: Date;
|
||||
recordsProcessed: number;
|
||||
recordsFailed: number;
|
||||
errorMessage?: string;
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
// 数据集成平台
|
||||
export class DataIntegrationPlatform {
|
||||
private static instance: DataIntegrationPlatform;
|
||||
private dataSources: Map<string, DataSourceConfig> = new Map();
|
||||
private transformationRules: Map<string, DataTransformationRule> = new Map();
|
||||
private integrationTasks: Map<string, IntegrationTask> = new Map();
|
||||
private integrationLogs: Map<string, IntegrationLog> = new Map();
|
||||
private eventBus: DomainEventBus;
|
||||
|
||||
private constructor() {
|
||||
this.eventBus = DomainEventBus.getInstance();
|
||||
}
|
||||
|
||||
static getInstance(): DataIntegrationPlatform {
|
||||
if (!DataIntegrationPlatform.instance) {
|
||||
DataIntegrationPlatform.instance = new DataIntegrationPlatform();
|
||||
}
|
||||
return DataIntegrationPlatform.instance;
|
||||
}
|
||||
|
||||
// 注册数据源
|
||||
async registerDataSource(dataSource: Omit<DataSourceConfig, 'id' | 'status' | 'createdAt' | 'lastUpdated'>): Promise<DataSourceConfig> {
|
||||
const id = `ds_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newDataSource: DataSourceConfig = {
|
||||
...dataSource,
|
||||
id,
|
||||
status: 'inactive',
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.dataSources.set(id, newDataSource);
|
||||
this.eventBus.publish('datasource.registered', newDataSource);
|
||||
return newDataSource;
|
||||
}
|
||||
|
||||
// 获取数据源信息
|
||||
getDataSource(dataSourceId: string): DataSourceConfig | undefined {
|
||||
return this.dataSources.get(dataSourceId);
|
||||
}
|
||||
|
||||
// 获取所有数据源
|
||||
getAllDataSources(filters?: {
|
||||
type?: string;
|
||||
status?: string;
|
||||
}): DataSourceConfig[] {
|
||||
let result = Array.from(this.dataSources.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.type) {
|
||||
result = result.filter(ds => ds.type === filters.type);
|
||||
}
|
||||
|
||||
if (filters.status) {
|
||||
result = result.filter(ds => ds.status === filters.status);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 更新数据源
|
||||
async updateDataSource(dataSourceId: string, updates: Partial<DataSourceConfig>): Promise<DataSourceConfig | null> {
|
||||
const dataSource = this.dataSources.get(dataSourceId);
|
||||
if (!dataSource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedDataSource = {
|
||||
...dataSource,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.dataSources.set(dataSourceId, updatedDataSource);
|
||||
this.eventBus.publish('datasource.updated', updatedDataSource);
|
||||
return updatedDataSource;
|
||||
}
|
||||
|
||||
// 测试数据源连接
|
||||
async testDataSourceConnection(dataSourceId: string): Promise<{ success: boolean; message: string }> {
|
||||
const dataSource = this.dataSources.get(dataSourceId);
|
||||
if (!dataSource) {
|
||||
return { success: false, message: 'DataSource not found' };
|
||||
}
|
||||
|
||||
try {
|
||||
// 这里应该有实际的连接测试逻辑
|
||||
// 暂时模拟测试
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
const success = Math.random() > 0.1; // 90% 成功率
|
||||
|
||||
if (success) {
|
||||
dataSource.status = 'active';
|
||||
this.dataSources.set(dataSourceId, dataSource);
|
||||
return { success: true, message: 'Connection successful' };
|
||||
} else {
|
||||
dataSource.status = 'error';
|
||||
this.dataSources.set(dataSourceId, dataSource);
|
||||
return { success: false, message: 'Connection failed' };
|
||||
}
|
||||
} catch (error) {
|
||||
dataSource.status = 'error';
|
||||
this.dataSources.set(dataSourceId, dataSource);
|
||||
return { success: false, message: error instanceof Error ? error.message : 'Unknown error' };
|
||||
}
|
||||
}
|
||||
|
||||
// 创建数据转换规则
|
||||
async createTransformationRule(rule: Omit<DataTransformationRule, 'id' | 'createdAt' | 'lastUpdated'>): Promise<DataTransformationRule> {
|
||||
const id = `rule_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newRule: DataTransformationRule = {
|
||||
...rule,
|
||||
id,
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.transformationRules.set(id, newRule);
|
||||
this.eventBus.publish('transformation.rule.created', newRule);
|
||||
return newRule;
|
||||
}
|
||||
|
||||
// 获取转换规则
|
||||
getTransformationRule(ruleId: string): DataTransformationRule | undefined {
|
||||
return this.transformationRules.get(ruleId);
|
||||
}
|
||||
|
||||
// 获取所有转换规则
|
||||
getAllTransformationRules(): DataTransformationRule[] {
|
||||
return Array.from(this.transformationRules.values());
|
||||
}
|
||||
|
||||
// 更新转换规则
|
||||
async updateTransformationRule(ruleId: string, updates: Partial<DataTransformationRule>): Promise<DataTransformationRule | null> {
|
||||
const rule = this.transformationRules.get(ruleId);
|
||||
if (!rule) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedRule = {
|
||||
...rule,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.transformationRules.set(ruleId, updatedRule);
|
||||
this.eventBus.publish('transformation.rule.updated', updatedRule);
|
||||
return updatedRule;
|
||||
}
|
||||
|
||||
// 创建集成任务
|
||||
async createIntegrationTask(task: Omit<IntegrationTask, 'id' | 'status' | 'lastRun' | 'nextRun' | 'createdAt' | 'lastUpdated'>): Promise<IntegrationTask> {
|
||||
const id = `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newTask: IntegrationTask = {
|
||||
...task,
|
||||
id,
|
||||
status: 'pending',
|
||||
lastRun: null,
|
||||
nextRun: this.calculateNextRun(task.schedule),
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.integrationTasks.set(id, newTask);
|
||||
this.eventBus.publish('integration.task.created', newTask);
|
||||
return newTask;
|
||||
}
|
||||
|
||||
// 获取集成任务
|
||||
getIntegrationTask(taskId: string): IntegrationTask | undefined {
|
||||
return this.integrationTasks.get(taskId);
|
||||
}
|
||||
|
||||
// 获取所有集成任务
|
||||
getAllIntegrationTasks(filters?: {
|
||||
status?: string;
|
||||
sourceDataSourceId?: string;
|
||||
targetDataSourceId?: string;
|
||||
}): IntegrationTask[] {
|
||||
let result = Array.from(this.integrationTasks.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.status) {
|
||||
result = result.filter(t => t.status === filters.status);
|
||||
}
|
||||
|
||||
if (filters.sourceDataSourceId) {
|
||||
result = result.filter(t => t.sourceDataSourceId === filters.sourceDataSourceId);
|
||||
}
|
||||
|
||||
if (filters.targetDataSourceId) {
|
||||
result = result.filter(t => t.targetDataSourceId === filters.targetDataSourceId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 更新集成任务
|
||||
async updateIntegrationTask(taskId: string, updates: Partial<IntegrationTask>): Promise<IntegrationTask | null> {
|
||||
const task = this.integrationTasks.get(taskId);
|
||||
if (!task) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedTask = {
|
||||
...task,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
if (updates.schedule) {
|
||||
updatedTask.nextRun = this.calculateNextRun(updates.schedule);
|
||||
}
|
||||
|
||||
this.integrationTasks.set(taskId, updatedTask);
|
||||
this.eventBus.publish('integration.task.updated', updatedTask);
|
||||
return updatedTask;
|
||||
}
|
||||
|
||||
// 执行集成任务
|
||||
async executeIntegrationTask(taskId: string): Promise<IntegrationLog> {
|
||||
const task = this.integrationTasks.get(taskId);
|
||||
if (!task) {
|
||||
throw new Error('Task not found');
|
||||
}
|
||||
|
||||
task.status = 'running';
|
||||
this.integrationTasks.set(taskId, task);
|
||||
this.eventBus.publish('integration.task.started', task);
|
||||
|
||||
const startTime = new Date();
|
||||
let recordsProcessed = 0;
|
||||
let recordsFailed = 0;
|
||||
let errorMessage: string | undefined;
|
||||
|
||||
try {
|
||||
// 这里应该有实际的任务执行逻辑
|
||||
// 暂时模拟执行
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
|
||||
recordsProcessed = Math.floor(Math.random() * 1000) + 100;
|
||||
recordsFailed = Math.floor(Math.random() * 10);
|
||||
|
||||
if (recordsFailed > 5) {
|
||||
throw new Error('Integration failed');
|
||||
}
|
||||
|
||||
task.status = 'success';
|
||||
task.lastRun = new Date();
|
||||
task.nextRun = this.calculateNextRun(task.schedule);
|
||||
} catch (error) {
|
||||
task.status = 'failed';
|
||||
errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
}
|
||||
|
||||
this.integrationTasks.set(taskId, task);
|
||||
|
||||
const endTime = new Date();
|
||||
const log: IntegrationLog = {
|
||||
id: `log_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||
taskId,
|
||||
status: task.status === 'success' ? 'success' : 'failed',
|
||||
startTime,
|
||||
endTime,
|
||||
recordsProcessed,
|
||||
recordsFailed,
|
||||
errorMessage
|
||||
};
|
||||
|
||||
this.integrationLogs.set(log.id, log);
|
||||
this.eventBus.publish('integration.task.completed', { task, log });
|
||||
return log;
|
||||
}
|
||||
|
||||
// 获取任务执行日志
|
||||
getIntegrationLog(logId: string): IntegrationLog | undefined {
|
||||
return this.integrationLogs.get(logId);
|
||||
}
|
||||
|
||||
// 获取任务的执行日志
|
||||
getTaskLogs(taskId: string): IntegrationLog[] {
|
||||
return Array.from(this.integrationLogs.values()).filter(log => log.taskId === taskId);
|
||||
}
|
||||
|
||||
// 计算下次执行时间
|
||||
private calculateNextRun(cronExpression: string): Date {
|
||||
// 这里应该有实际的cron表达式解析逻辑
|
||||
// 暂时返回当前时间后1小时
|
||||
const nextRun = new Date();
|
||||
nextRun.setHours(nextRun.getHours() + 1);
|
||||
return nextRun;
|
||||
}
|
||||
|
||||
// 启动所有定时任务
|
||||
async startScheduledTasks(): Promise<void> {
|
||||
// 这里应该有实际的定时任务启动逻辑
|
||||
// 暂时模拟启动
|
||||
this.eventBus.publish('integration.tasks.started', { timestamp: new Date() });
|
||||
}
|
||||
|
||||
// 停止所有定时任务
|
||||
async stopScheduledTasks(): Promise<void> {
|
||||
// 这里应该有实际的定时任务停止逻辑
|
||||
// 暂时模拟停止
|
||||
this.eventBus.publish('integration.tasks.stopped', { timestamp: new Date() });
|
||||
}
|
||||
|
||||
// 获取平台状态
|
||||
getPlatformStatus(): {
|
||||
totalDataSources: number;
|
||||
activeDataSources: number;
|
||||
totalTasks: number;
|
||||
runningTasks: number;
|
||||
successTasks: number;
|
||||
failedTasks: number;
|
||||
totalLogs: number;
|
||||
} {
|
||||
const dataSources = Array.from(this.dataSources.values());
|
||||
const tasks = Array.from(this.integrationTasks.values());
|
||||
const logs = Array.from(this.integrationLogs.values());
|
||||
|
||||
return {
|
||||
totalDataSources: dataSources.length,
|
||||
activeDataSources: dataSources.filter(ds => ds.status === 'active').length,
|
||||
totalTasks: tasks.length,
|
||||
runningTasks: tasks.filter(t => t.status === 'running').length,
|
||||
successTasks: tasks.filter(t => t.status === 'success').length,
|
||||
failedTasks: tasks.filter(t => t.status === 'failed').length,
|
||||
totalLogs: logs.length
|
||||
};
|
||||
}
|
||||
}
|
||||
399
server/src/core/data/DataQualityService.ts
Normal file
399
server/src/core/data/DataQualityService.ts
Normal file
@@ -0,0 +1,399 @@
|
||||
import { DomainEventBus } from '../runtime/DomainEventBus';
|
||||
|
||||
// 数据质量规则
|
||||
export interface DataQualityRule {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
type: 'validation' | 'completeness' | 'accuracy' | 'consistency' | 'timeliness';
|
||||
expression: string; // 规则表达式
|
||||
severity: 'low' | 'medium' | 'high';
|
||||
threshold: number;
|
||||
enabled: boolean;
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
}
|
||||
|
||||
// 数据质量检查结果
|
||||
export interface QualityCheckResult {
|
||||
id: string;
|
||||
ruleId: string;
|
||||
dataSourceId: string;
|
||||
entity: string; // 表名或实体名
|
||||
recordsChecked: number;
|
||||
recordsFailed: number;
|
||||
failureRate: number;
|
||||
status: 'pass' | 'warning' | 'fail';
|
||||
timestamp: Date;
|
||||
details?: Record<string, any>;
|
||||
}
|
||||
|
||||
// 数据质量指标
|
||||
export interface DataQualityMetrics {
|
||||
dataSourceId: string;
|
||||
entity: string;
|
||||
completeness: number; // 完整性百分比
|
||||
accuracy: number; // 准确性百分比
|
||||
consistency: number; // 一致性百分比
|
||||
timeliness: number; // 及时性百分比
|
||||
overallScore: number; // 总体得分
|
||||
lastUpdated: Date;
|
||||
}
|
||||
|
||||
// 数据质量服务
|
||||
export class DataQualityService {
|
||||
private static instance: DataQualityService;
|
||||
private qualityRules: Map<string, DataQualityRule> = new Map();
|
||||
private checkResults: Map<string, QualityCheckResult> = new Map();
|
||||
private qualityMetrics: Map<string, DataQualityMetrics> = new Map();
|
||||
private eventBus: DomainEventBus;
|
||||
|
||||
private constructor() {
|
||||
this.eventBus = DomainEventBus.getInstance();
|
||||
}
|
||||
|
||||
static getInstance(): DataQualityService {
|
||||
if (!DataQualityService.instance) {
|
||||
DataQualityService.instance = new DataQualityService();
|
||||
}
|
||||
return DataQualityService.instance;
|
||||
}
|
||||
|
||||
// 创建数据质量规则
|
||||
async createQualityRule(rule: Omit<DataQualityRule, 'id' | 'createdAt' | 'lastUpdated'>): Promise<DataQualityRule> {
|
||||
const id = `rule_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newRule: DataQualityRule = {
|
||||
...rule,
|
||||
id,
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.qualityRules.set(id, newRule);
|
||||
this.eventBus.publish('quality.rule.created', newRule);
|
||||
return newRule;
|
||||
}
|
||||
|
||||
// 获取质量规则
|
||||
getQualityRule(ruleId: string): DataQualityRule | undefined {
|
||||
return this.qualityRules.get(ruleId);
|
||||
}
|
||||
|
||||
// 获取所有质量规则
|
||||
getAllQualityRules(filters?: {
|
||||
type?: string;
|
||||
severity?: string;
|
||||
enabled?: boolean;
|
||||
}): DataQualityRule[] {
|
||||
let result = Array.from(this.qualityRules.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.type) {
|
||||
result = result.filter(r => r.type === filters.type);
|
||||
}
|
||||
|
||||
if (filters.severity) {
|
||||
result = result.filter(r => r.severity === filters.severity);
|
||||
}
|
||||
|
||||
if (filters.enabled !== undefined) {
|
||||
result = result.filter(r => r.enabled === filters.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 更新质量规则
|
||||
async updateQualityRule(ruleId: string, updates: Partial<DataQualityRule>): Promise<DataQualityRule | null> {
|
||||
const rule = this.qualityRules.get(ruleId);
|
||||
if (!rule) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedRule = {
|
||||
...rule,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.qualityRules.set(ruleId, updatedRule);
|
||||
this.eventBus.publish('quality.rule.updated', updatedRule);
|
||||
return updatedRule;
|
||||
}
|
||||
|
||||
// 启用/禁用质量规则
|
||||
async toggleQualityRule(ruleId: string, enabled: boolean): Promise<boolean> {
|
||||
const rule = this.qualityRules.get(ruleId);
|
||||
if (!rule) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rule.enabled = enabled;
|
||||
rule.lastUpdated = new Date();
|
||||
this.qualityRules.set(ruleId, rule);
|
||||
this.eventBus.publish('quality.rule.toggled', rule);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 执行数据质量检查
|
||||
async runQualityCheck(dataSourceId: string, entity: string): Promise<QualityCheckResult[]> {
|
||||
const enabledRules = this.getAllQualityRules({ enabled: true });
|
||||
const results: QualityCheckResult[] = [];
|
||||
|
||||
for (const rule of enabledRules) {
|
||||
const result = await this.checkRule(dataSourceId, entity, rule);
|
||||
results.push(result);
|
||||
}
|
||||
|
||||
// 更新数据质量指标
|
||||
await this.updateQualityMetrics(dataSourceId, entity, results);
|
||||
|
||||
this.eventBus.publish('quality.check.completed', { dataSourceId, entity, results, timestamp: new Date() });
|
||||
return results;
|
||||
}
|
||||
|
||||
// 检查单个规则
|
||||
private async checkRule(dataSourceId: string, entity: string, rule: DataQualityRule): Promise<QualityCheckResult> {
|
||||
// 这里应该有实际的规则检查逻辑
|
||||
// 暂时模拟检查
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
|
||||
const recordsChecked = Math.floor(Math.random() * 1000) + 100;
|
||||
const recordsFailed = Math.floor(Math.random() * 50);
|
||||
const failureRate = recordsFailed / recordsChecked;
|
||||
|
||||
let status: 'pass' | 'warning' | 'fail';
|
||||
if (failureRate === 0) {
|
||||
status = 'pass';
|
||||
} else if (failureRate < rule.threshold) {
|
||||
status = 'warning';
|
||||
} else {
|
||||
status = 'fail';
|
||||
}
|
||||
|
||||
const result: QualityCheckResult = {
|
||||
id: `result_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||
ruleId: rule.id,
|
||||
dataSourceId,
|
||||
entity,
|
||||
recordsChecked,
|
||||
recordsFailed,
|
||||
failureRate,
|
||||
status,
|
||||
timestamp: new Date()
|
||||
};
|
||||
|
||||
this.checkResults.set(result.id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 更新数据质量指标
|
||||
private async updateQualityMetrics(dataSourceId: string, entity: string, results: QualityCheckResult[]): Promise<void> {
|
||||
const key = `${dataSourceId}:${entity}`;
|
||||
|
||||
// 计算各项指标
|
||||
let completeness = 100;
|
||||
let accuracy = 100;
|
||||
let consistency = 100;
|
||||
let timeliness = 100;
|
||||
|
||||
for (const result of results) {
|
||||
const rule = this.qualityRules.get(result.ruleId);
|
||||
if (rule) {
|
||||
const score = (1 - result.failureRate) * 100;
|
||||
switch (rule.type) {
|
||||
case 'completeness':
|
||||
completeness = score;
|
||||
break;
|
||||
case 'accuracy':
|
||||
accuracy = score;
|
||||
break;
|
||||
case 'consistency':
|
||||
consistency = score;
|
||||
break;
|
||||
case 'timeliness':
|
||||
timeliness = score;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const overallScore = (completeness + accuracy + consistency + timeliness) / 4;
|
||||
|
||||
const metrics: DataQualityMetrics = {
|
||||
dataSourceId,
|
||||
entity,
|
||||
completeness,
|
||||
accuracy,
|
||||
consistency,
|
||||
timeliness,
|
||||
overallScore,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.qualityMetrics.set(key, metrics);
|
||||
this.eventBus.publish('quality.metrics.updated', metrics);
|
||||
}
|
||||
|
||||
// 获取数据质量指标
|
||||
getQualityMetrics(dataSourceId: string, entity: string): DataQualityMetrics | undefined {
|
||||
const key = `${dataSourceId}:${entity}`;
|
||||
return this.qualityMetrics.get(key);
|
||||
}
|
||||
|
||||
// 获取所有数据质量指标
|
||||
getAllQualityMetrics(filters?: {
|
||||
dataSourceId?: string;
|
||||
minScore?: number;
|
||||
}): DataQualityMetrics[] {
|
||||
let result = Array.from(this.qualityMetrics.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.dataSourceId) {
|
||||
result = result.filter(m => m.dataSourceId === filters.dataSourceId);
|
||||
}
|
||||
|
||||
if (filters.minScore !== undefined) {
|
||||
result = result.filter(m => m.overallScore >= filters.minScore!);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取质量检查结果
|
||||
getQualityCheckResult(resultId: string): QualityCheckResult | undefined {
|
||||
return this.checkResults.get(resultId);
|
||||
}
|
||||
|
||||
// 获取数据源的质量检查结果
|
||||
getDataSourceCheckResults(dataSourceId: string): QualityCheckResult[] {
|
||||
return Array.from(this.checkResults.values()).filter(r => r.dataSourceId === dataSourceId);
|
||||
}
|
||||
|
||||
// 获取规则的质量检查结果
|
||||
getRuleCheckResults(ruleId: string): QualityCheckResult[] {
|
||||
return Array.from(this.checkResults.values()).filter(r => r.ruleId === ruleId);
|
||||
}
|
||||
|
||||
// 生成数据质量报告
|
||||
async generateQualityReport(dataSourceId?: string): Promise<{
|
||||
summary: {
|
||||
totalChecks: number;
|
||||
passedChecks: number;
|
||||
warningChecks: number;
|
||||
failedChecks: number;
|
||||
averageScore: number;
|
||||
};
|
||||
details: QualityCheckResult[];
|
||||
metrics: DataQualityMetrics[];
|
||||
}> {
|
||||
let results = Array.from(this.checkResults.values());
|
||||
let metrics = Array.from(this.qualityMetrics.values());
|
||||
|
||||
if (dataSourceId) {
|
||||
results = results.filter(r => r.dataSourceId === dataSourceId);
|
||||
metrics = metrics.filter(m => m.dataSourceId === dataSourceId);
|
||||
}
|
||||
|
||||
const passedChecks = results.filter(r => r.status === 'pass').length;
|
||||
const warningChecks = results.filter(r => r.status === 'warning').length;
|
||||
const failedChecks = results.filter(r => r.status === 'fail').length;
|
||||
|
||||
const averageScore = metrics.length > 0
|
||||
? metrics.reduce((sum, m) => sum + m.overallScore, 0) / metrics.length
|
||||
: 0;
|
||||
|
||||
return {
|
||||
summary: {
|
||||
totalChecks: results.length,
|
||||
passedChecks,
|
||||
warningChecks,
|
||||
failedChecks,
|
||||
averageScore
|
||||
},
|
||||
details: results,
|
||||
metrics
|
||||
};
|
||||
}
|
||||
|
||||
// 自动修复数据质量问题
|
||||
async autoFixQualityIssues(dataSourceId: string, entity: string, ruleId: string): Promise<{
|
||||
success: boolean;
|
||||
fixedRecords: number;
|
||||
message: string;
|
||||
}> {
|
||||
// 这里应该有实际的自动修复逻辑
|
||||
// 暂时模拟修复
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const fixedRecords = Math.floor(Math.random() * 50);
|
||||
const success = Math.random() > 0.2; // 80% 成功率
|
||||
|
||||
return {
|
||||
success,
|
||||
fixedRecords,
|
||||
message: success
|
||||
? `Fixed ${fixedRecords} records`
|
||||
: 'Auto-fix failed'
|
||||
};
|
||||
}
|
||||
|
||||
// 获取数据质量趋势
|
||||
getQualityTrend(dataSourceId: string, entity: string, days: number = 30): {
|
||||
dates: string[];
|
||||
scores: number[];
|
||||
} {
|
||||
// 这里应该有实际的趋势分析逻辑
|
||||
// 暂时返回模拟数据
|
||||
const dates: string[] = [];
|
||||
const scores: number[] = [];
|
||||
|
||||
for (let i = days - 1; i >= 0; i--) {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() - i);
|
||||
dates.push(date.toISOString().split('T')[0]);
|
||||
scores.push(Math.random() * 20 + 80); // 80-100 之间的随机数
|
||||
}
|
||||
|
||||
return {
|
||||
dates,
|
||||
scores
|
||||
};
|
||||
}
|
||||
|
||||
// 获取数据质量统计信息
|
||||
getQualityStats(): {
|
||||
totalRules: number;
|
||||
enabledRules: number;
|
||||
totalChecks: number;
|
||||
passedChecks: number;
|
||||
warningChecks: number;
|
||||
failedChecks: number;
|
||||
averageScore: number;
|
||||
} {
|
||||
const rules = Array.from(this.qualityRules.values());
|
||||
const results = Array.from(this.checkResults.values());
|
||||
const metrics = Array.from(this.qualityMetrics.values());
|
||||
|
||||
const passedChecks = results.filter(r => r.status === 'pass').length;
|
||||
const warningChecks = results.filter(r => r.status === 'warning').length;
|
||||
const failedChecks = results.filter(r => r.status === 'fail').length;
|
||||
|
||||
const averageScore = metrics.length > 0
|
||||
? metrics.reduce((sum, m) => sum + m.overallScore, 0) / metrics.length
|
||||
: 0;
|
||||
|
||||
return {
|
||||
totalRules: rules.length,
|
||||
enabledRules: rules.filter(r => r.enabled).length,
|
||||
totalChecks: results.length,
|
||||
passedChecks,
|
||||
warningChecks,
|
||||
failedChecks,
|
||||
averageScore
|
||||
};
|
||||
}
|
||||
}
|
||||
133
server/src/core/engine/DataStateMachine.ts
Normal file
133
server/src/core/engine/DataStateMachine.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import { StateMachine } from 'xstate';
|
||||
|
||||
// 数据状态定义
|
||||
export type DataState = 'raw' | 'validating' | 'valid' | 'invalid' | 'processing' | 'processed' | 'error';
|
||||
|
||||
// 数据状态事件
|
||||
export type DataEvent =
|
||||
| { type: 'VALIDATE' }
|
||||
| { type: 'VALID' }
|
||||
| { type: 'INVALID' }
|
||||
| { type: 'PROCESS' }
|
||||
| { type: 'PROCESS_SUCCESS' }
|
||||
| { type: 'PROCESS_ERROR' }
|
||||
| { type: 'RETRY' };
|
||||
|
||||
// 数据状态上下文
|
||||
export interface DataContext {
|
||||
dataId: string;
|
||||
tenantId: string;
|
||||
shopId: string;
|
||||
taskId: string;
|
||||
traceId: string;
|
||||
businessType: 'TOC' | 'TOB';
|
||||
lastUpdated: string;
|
||||
updatedBy: string;
|
||||
dataType: string;
|
||||
source: string;
|
||||
}
|
||||
|
||||
// 数据状态机
|
||||
export const dataStateMachine = StateMachine<DataContext, DataState, DataEvent>({
|
||||
id: 'data',
|
||||
initial: 'raw',
|
||||
states: {
|
||||
raw: {
|
||||
on: {
|
||||
VALIDATE: 'validating'
|
||||
}
|
||||
},
|
||||
validating: {
|
||||
on: {
|
||||
VALID: 'valid',
|
||||
INVALID: 'invalid'
|
||||
}
|
||||
},
|
||||
valid: {
|
||||
on: {
|
||||
PROCESS: 'processing'
|
||||
}
|
||||
},
|
||||
invalid: {
|
||||
on: {
|
||||
VALIDATE: 'validating'
|
||||
}
|
||||
},
|
||||
processing: {
|
||||
on: {
|
||||
PROCESS_SUCCESS: 'processed',
|
||||
PROCESS_ERROR: 'error'
|
||||
}
|
||||
},
|
||||
processed: {
|
||||
type: 'final'
|
||||
},
|
||||
error: {
|
||||
on: {
|
||||
RETRY: 'processing'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 状态变更服务
|
||||
export class DataStateMachineService {
|
||||
private static instance: DataStateMachineService;
|
||||
|
||||
static getInstance(): DataStateMachineService {
|
||||
if (!DataStateMachineService.instance) {
|
||||
DataStateMachineService.instance = new DataStateMachineService();
|
||||
}
|
||||
return DataStateMachineService.instance;
|
||||
}
|
||||
|
||||
async transition(
|
||||
currentState: DataState,
|
||||
event: DataEvent,
|
||||
context: DataContext
|
||||
): Promise<{
|
||||
newState: DataState;
|
||||
context: DataContext;
|
||||
}> {
|
||||
const state = dataStateMachine.transition(currentState, event);
|
||||
|
||||
// 更新上下文
|
||||
const updatedContext = {
|
||||
...context,
|
||||
lastUpdated: new Date().toISOString(),
|
||||
};
|
||||
|
||||
// 记录状态变更日志
|
||||
this.logStateChange(updatedContext, currentState, state.value);
|
||||
|
||||
return {
|
||||
newState: state.value,
|
||||
context: updatedContext
|
||||
};
|
||||
}
|
||||
|
||||
private logStateChange(
|
||||
context: DataContext,
|
||||
fromState: DataState,
|
||||
toState: DataState
|
||||
): void {
|
||||
console.log(`[DataStateMachine] Data ${context.dataId} transitioned from ${fromState} to ${toState}`, {
|
||||
...context,
|
||||
fromState,
|
||||
toState,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
// 验证状态变更是否有效
|
||||
isValidTransition(fromState: DataState, event: DataEvent): boolean {
|
||||
const state = dataStateMachine.transition(fromState, event);
|
||||
return state.value !== fromState || state.matches(fromState);
|
||||
}
|
||||
|
||||
// 获取当前状态下可执行的事件
|
||||
getAvailableEvents(state: DataState): DataEvent['type'][] {
|
||||
const stateNode = dataStateMachine.getStateNode(state);
|
||||
return Object.keys(stateNode.on || {});
|
||||
}
|
||||
}
|
||||
141
server/src/core/engine/OrderStateMachine.ts
Normal file
141
server/src/core/engine/OrderStateMachine.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { StateMachine } from 'xstate';
|
||||
|
||||
// 订单状态定义
|
||||
export type OrderState = 'pending' | 'paid' | 'split' | 'processing' | 'shipped' | 'completed' | 'refunded' | 'cancelled';
|
||||
|
||||
// 订单状态事件
|
||||
export type OrderEvent =
|
||||
| { type: 'PAY' }
|
||||
| { type: 'SPLIT' }
|
||||
| { type: 'PROCESS' }
|
||||
| { type: 'SHIP' }
|
||||
| { type: 'COMPLETE' }
|
||||
| { type: 'REFUND' }
|
||||
| { type: 'CANCEL' };
|
||||
|
||||
// 订单状态上下文
|
||||
export interface OrderContext {
|
||||
orderId: string;
|
||||
tenantId: string;
|
||||
shopId: string;
|
||||
taskId: string;
|
||||
traceId: string;
|
||||
businessType: 'TOC' | 'TOB';
|
||||
lastUpdated: string;
|
||||
updatedBy: string;
|
||||
amount: number;
|
||||
customerId: string;
|
||||
}
|
||||
|
||||
// 订单状态机
|
||||
export const orderStateMachine = StateMachine<OrderContext, OrderState, OrderEvent>({
|
||||
id: 'order',
|
||||
initial: 'pending',
|
||||
states: {
|
||||
pending: {
|
||||
on: {
|
||||
PAY: 'paid',
|
||||
CANCEL: 'cancelled'
|
||||
}
|
||||
},
|
||||
paid: {
|
||||
on: {
|
||||
SPLIT: 'split',
|
||||
PROCESS: 'processing',
|
||||
REFUND: 'refunded',
|
||||
CANCEL: 'cancelled'
|
||||
}
|
||||
},
|
||||
split: {
|
||||
on: {
|
||||
PROCESS: 'processing'
|
||||
}
|
||||
},
|
||||
processing: {
|
||||
on: {
|
||||
SHIP: 'shipped',
|
||||
REFUND: 'refunded',
|
||||
CANCEL: 'cancelled'
|
||||
}
|
||||
},
|
||||
shipped: {
|
||||
on: {
|
||||
COMPLETE: 'completed',
|
||||
REFUND: 'refunded'
|
||||
}
|
||||
},
|
||||
completed: {
|
||||
on: {
|
||||
REFUND: 'refunded'
|
||||
}
|
||||
},
|
||||
refunded: {
|
||||
type: 'final'
|
||||
},
|
||||
cancelled: {
|
||||
type: 'final'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 状态变更服务
|
||||
export class OrderStateMachineService {
|
||||
private static instance: OrderStateMachineService;
|
||||
|
||||
static getInstance(): OrderStateMachineService {
|
||||
if (!OrderStateMachineService.instance) {
|
||||
OrderStateMachineService.instance = new OrderStateMachineService();
|
||||
}
|
||||
return OrderStateMachineService.instance;
|
||||
}
|
||||
|
||||
async transition(
|
||||
currentState: OrderState,
|
||||
event: OrderEvent,
|
||||
context: OrderContext
|
||||
): Promise<{
|
||||
newState: OrderState;
|
||||
context: OrderContext;
|
||||
}> {
|
||||
const state = orderStateMachine.transition(currentState, event);
|
||||
|
||||
// 更新上下文
|
||||
const updatedContext = {
|
||||
...context,
|
||||
lastUpdated: new Date().toISOString(),
|
||||
};
|
||||
|
||||
// 记录状态变更日志
|
||||
this.logStateChange(updatedContext, currentState, state.value);
|
||||
|
||||
return {
|
||||
newState: state.value,
|
||||
context: updatedContext
|
||||
};
|
||||
}
|
||||
|
||||
private logStateChange(
|
||||
context: OrderContext,
|
||||
fromState: OrderState,
|
||||
toState: OrderState
|
||||
): void {
|
||||
console.log(`[OrderStateMachine] Order ${context.orderId} transitioned from ${fromState} to ${toState}`, {
|
||||
...context,
|
||||
fromState,
|
||||
toState,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
// 验证状态变更是否有效
|
||||
isValidTransition(fromState: OrderState, event: OrderEvent): boolean {
|
||||
const state = orderStateMachine.transition(fromState, event);
|
||||
return state.value !== fromState || state.matches(fromState);
|
||||
}
|
||||
|
||||
// 获取当前状态下可执行的事件
|
||||
getAvailableEvents(state: OrderState): OrderEvent['type'][] {
|
||||
const stateNode = orderStateMachine.getStateNode(state);
|
||||
return Object.keys(stateNode.on || {});
|
||||
}
|
||||
}
|
||||
124
server/src/core/engine/ProductStateMachine.ts
Normal file
124
server/src/core/engine/ProductStateMachine.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { StateMachine } from 'xstate';
|
||||
|
||||
// 商品状态定义
|
||||
export type ProductState = 'draft' | 'pending_approval' | 'active' | 'inactive' | 'discontinued';
|
||||
|
||||
// 商品状态事件
|
||||
export type ProductEvent =
|
||||
| { type: 'SUBMIT_FOR_APPROVAL' }
|
||||
| { type: 'APPROVE' }
|
||||
| { type: 'REJECT' }
|
||||
| { type: 'ACTIVATE' }
|
||||
| { type: 'DEACTIVATE' }
|
||||
| { type: 'DISCONTINUE' }
|
||||
| { type: 'REACTIVATE' };
|
||||
|
||||
// 商品状态上下文
|
||||
export interface ProductContext {
|
||||
productId: string;
|
||||
tenantId: string;
|
||||
shopId: string;
|
||||
taskId: string;
|
||||
traceId: string;
|
||||
businessType: 'TOC' | 'TOB';
|
||||
lastUpdated: string;
|
||||
updatedBy: string;
|
||||
}
|
||||
|
||||
// 商品状态机
|
||||
export const productStateMachine = StateMachine<ProductContext, ProductState, ProductEvent>({
|
||||
id: 'product',
|
||||
initial: 'draft',
|
||||
states: {
|
||||
draft: {
|
||||
on: {
|
||||
SUBMIT_FOR_APPROVAL: 'pending_approval'
|
||||
}
|
||||
},
|
||||
pending_approval: {
|
||||
on: {
|
||||
APPROVE: 'active',
|
||||
REJECT: 'draft'
|
||||
}
|
||||
},
|
||||
active: {
|
||||
on: {
|
||||
DEACTIVATE: 'inactive',
|
||||
DISCONTINUE: 'discontinued'
|
||||
}
|
||||
},
|
||||
inactive: {
|
||||
on: {
|
||||
ACTIVATE: 'active',
|
||||
DISCONTINUE: 'discontinued'
|
||||
}
|
||||
},
|
||||
discontinued: {
|
||||
on: {
|
||||
REACTIVATE: 'draft'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 状态变更服务
|
||||
export class ProductStateMachineService {
|
||||
private static instance: ProductStateMachineService;
|
||||
|
||||
static getInstance(): ProductStateMachineService {
|
||||
if (!ProductStateMachineService.instance) {
|
||||
ProductStateMachineService.instance = new ProductStateMachineService();
|
||||
}
|
||||
return ProductStateMachineService.instance;
|
||||
}
|
||||
|
||||
async transition(
|
||||
currentState: ProductState,
|
||||
event: ProductEvent,
|
||||
context: ProductContext
|
||||
): Promise<{
|
||||
newState: ProductState;
|
||||
context: ProductContext;
|
||||
}> {
|
||||
const state = productStateMachine.transition(currentState, event);
|
||||
|
||||
// 更新上下文
|
||||
const updatedContext = {
|
||||
...context,
|
||||
lastUpdated: new Date().toISOString(),
|
||||
};
|
||||
|
||||
// 记录状态变更日志
|
||||
this.logStateChange(updatedContext, currentState, state.value);
|
||||
|
||||
return {
|
||||
newState: state.value,
|
||||
context: updatedContext
|
||||
};
|
||||
}
|
||||
|
||||
private logStateChange(
|
||||
context: ProductContext,
|
||||
fromState: ProductState,
|
||||
toState: ProductState
|
||||
): void {
|
||||
console.log(`[ProductStateMachine] Product ${context.productId} transitioned from ${fromState} to ${toState}`, {
|
||||
...context,
|
||||
fromState,
|
||||
toState,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
// 验证状态变更是否有效
|
||||
isValidTransition(fromState: ProductState, event: ProductEvent): boolean {
|
||||
const state = productStateMachine.transition(fromState, event);
|
||||
return state.value !== fromState || state.matches(fromState);
|
||||
}
|
||||
|
||||
// 获取当前状态下可执行的事件
|
||||
getAvailableEvents(state: ProductState): ProductEvent['type'][] {
|
||||
const stateNode = productStateMachine.getStateNode(state);
|
||||
return Object.keys(stateNode.on || {});
|
||||
}
|
||||
}
|
||||
357
server/src/core/exception/ExceptionKnowledgeBase.ts
Normal file
357
server/src/core/exception/ExceptionKnowledgeBase.ts
Normal file
@@ -0,0 +1,357 @@
|
||||
import { DomainEventBus } from '../runtime/DomainEventBus';
|
||||
|
||||
// 异常知识条目
|
||||
export interface ExceptionKnowledgeItem {
|
||||
id: string;
|
||||
exceptionType: string;
|
||||
messagePattern: string;
|
||||
description: string;
|
||||
cause: string;
|
||||
solution: string;
|
||||
prevention: string;
|
||||
severity: 'low' | 'medium' | 'high' | 'critical';
|
||||
frequency: number;
|
||||
references?: string[];
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
lastSeen: Date;
|
||||
}
|
||||
|
||||
// 异常知识查询结果
|
||||
export interface ExceptionKnowledgeQueryResult {
|
||||
items: ExceptionKnowledgeItem[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
query: string;
|
||||
filters?: Record<string, string>;
|
||||
}
|
||||
|
||||
// 异常知识统计
|
||||
export interface ExceptionKnowledgeStats {
|
||||
totalItems: number;
|
||||
bySeverity: {
|
||||
low: number;
|
||||
medium: number;
|
||||
high: number;
|
||||
critical: number;
|
||||
};
|
||||
byType: Record<string, number>;
|
||||
mostFrequent: ExceptionKnowledgeItem[];
|
||||
recentlyUpdated: ExceptionKnowledgeItem[];
|
||||
averageFrequency: number;
|
||||
}
|
||||
|
||||
// 异常知识库
|
||||
export class ExceptionKnowledgeBase {
|
||||
private static instance: ExceptionKnowledgeBase;
|
||||
private knowledgeItems: Map<string, ExceptionKnowledgeItem> = new Map();
|
||||
private eventBus: DomainEventBus;
|
||||
|
||||
private constructor() {
|
||||
this.eventBus = DomainEventBus.getInstance();
|
||||
}
|
||||
|
||||
static getInstance(): ExceptionKnowledgeBase {
|
||||
if (!ExceptionKnowledgeBase.instance) {
|
||||
ExceptionKnowledgeBase.instance = new ExceptionKnowledgeBase();
|
||||
}
|
||||
return ExceptionKnowledgeBase.instance;
|
||||
}
|
||||
|
||||
// 添加异常知识条目
|
||||
async addKnowledgeItem(item: Omit<ExceptionKnowledgeItem, 'id' | 'frequency' | 'createdAt' | 'lastUpdated' | 'lastSeen'>): Promise<ExceptionKnowledgeItem> {
|
||||
const id = `knowledge_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newItem: ExceptionKnowledgeItem = {
|
||||
...item,
|
||||
id,
|
||||
frequency: 1,
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date(),
|
||||
lastSeen: new Date()
|
||||
};
|
||||
|
||||
this.knowledgeItems.set(id, newItem);
|
||||
this.eventBus.publish('exception.knowledge.added', newItem);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
// 获取异常知识条目
|
||||
getKnowledgeItem(itemId: string): ExceptionKnowledgeItem | undefined {
|
||||
return this.knowledgeItems.get(itemId);
|
||||
}
|
||||
|
||||
// 获取所有异常知识条目
|
||||
getAllKnowledgeItems(filters?: {
|
||||
severity?: string;
|
||||
exceptionType?: string;
|
||||
minFrequency?: number;
|
||||
}): ExceptionKnowledgeItem[] {
|
||||
let result = Array.from(this.knowledgeItems.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.severity) {
|
||||
result = result.filter(item => item.severity === filters.severity);
|
||||
}
|
||||
|
||||
if (filters.exceptionType) {
|
||||
result = result.filter(item => item.exceptionType === filters.exceptionType);
|
||||
}
|
||||
|
||||
if (filters.minFrequency !== undefined) {
|
||||
result = result.filter(item => item.frequency >= filters.minFrequency!);
|
||||
}
|
||||
}
|
||||
|
||||
return result.sort((a, b) => b.frequency - a.frequency);
|
||||
}
|
||||
|
||||
// 更新异常知识条目
|
||||
async updateKnowledgeItem(itemId: string, updates: Partial<ExceptionKnowledgeItem>): Promise<ExceptionKnowledgeItem | null> {
|
||||
const item = this.knowledgeItems.get(itemId);
|
||||
if (!item) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedItem = {
|
||||
...item,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.knowledgeItems.set(itemId, updatedItem);
|
||||
this.eventBus.publish('exception.knowledge.updated', updatedItem);
|
||||
return updatedItem;
|
||||
}
|
||||
|
||||
// 删除异常知识条目
|
||||
async deleteKnowledgeItem(itemId: string): Promise<boolean> {
|
||||
const item = this.knowledgeItems.get(itemId);
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.knowledgeItems.delete(itemId);
|
||||
this.eventBus.publish('exception.knowledge.deleted', item);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 搜索异常知识
|
||||
searchKnowledge(query: string, page: number = 1, pageSize: number = 10, filters?: Record<string, string>): ExceptionKnowledgeQueryResult {
|
||||
let results = Array.from(this.knowledgeItems.values());
|
||||
|
||||
// 应用过滤器
|
||||
if (filters) {
|
||||
for (const [key, value] of Object.entries(filters)) {
|
||||
if (key === 'severity') {
|
||||
results = results.filter(item => item.severity === value);
|
||||
} else if (key === 'exceptionType') {
|
||||
results = results.filter(item => item.exceptionType === value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索查询
|
||||
if (query) {
|
||||
const lowerQuery = query.toLowerCase();
|
||||
results = results.filter(item =>
|
||||
item.exceptionType.toLowerCase().includes(lowerQuery) ||
|
||||
item.messagePattern.toLowerCase().includes(lowerQuery) ||
|
||||
item.description.toLowerCase().includes(lowerQuery) ||
|
||||
item.cause.toLowerCase().includes(lowerQuery) ||
|
||||
item.solution.toLowerCase().includes(lowerQuery)
|
||||
);
|
||||
}
|
||||
|
||||
// 排序
|
||||
results.sort((a, b) => b.frequency - a.frequency);
|
||||
|
||||
// 分页
|
||||
const total = results.length;
|
||||
const start = (page - 1) * pageSize;
|
||||
const end = start + pageSize;
|
||||
const paginatedResults = results.slice(start, end);
|
||||
|
||||
return {
|
||||
items: paginatedResults,
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
query,
|
||||
filters
|
||||
};
|
||||
}
|
||||
|
||||
// 匹配异常
|
||||
matchException(exceptionType: string, message: string): ExceptionKnowledgeItem[] {
|
||||
const results: ExceptionKnowledgeItem[] = [];
|
||||
|
||||
for (const item of this.knowledgeItems.values()) {
|
||||
// 检查异常类型匹配
|
||||
if (item.exceptionType === exceptionType) {
|
||||
// 检查消息模式匹配
|
||||
try {
|
||||
const regex = new RegExp(item.messagePattern);
|
||||
if (regex.test(message)) {
|
||||
results.push(item);
|
||||
}
|
||||
} catch (error) {
|
||||
// 正则表达式错误,使用简单字符串匹配
|
||||
if (message.includes(item.messagePattern)) {
|
||||
results.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按频率排序
|
||||
return results.sort((a, b) => b.frequency - a.frequency);
|
||||
}
|
||||
|
||||
// 增加异常频率
|
||||
async incrementFrequency(itemId: string): Promise<ExceptionKnowledgeItem | null> {
|
||||
const item = this.knowledgeItems.get(itemId);
|
||||
if (!item) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedItem = {
|
||||
...item,
|
||||
frequency: item.frequency + 1,
|
||||
lastSeen: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.knowledgeItems.set(itemId, updatedItem);
|
||||
this.eventBus.publish('exception.knowledge.frequency.updated', updatedItem);
|
||||
return updatedItem;
|
||||
}
|
||||
|
||||
// 批量增加异常频率
|
||||
async batchIncrementFrequency(itemIds: string[]): Promise<ExceptionKnowledgeItem[]> {
|
||||
const updatedItems: ExceptionKnowledgeItem[] = [];
|
||||
|
||||
for (const itemId of itemIds) {
|
||||
const updatedItem = await this.incrementFrequency(itemId);
|
||||
if (updatedItem) {
|
||||
updatedItems.push(updatedItem);
|
||||
}
|
||||
}
|
||||
|
||||
return updatedItems;
|
||||
}
|
||||
|
||||
// 获取异常知识统计
|
||||
getKnowledgeStats(): ExceptionKnowledgeStats {
|
||||
const items = Array.from(this.knowledgeItems.values());
|
||||
const totalItems = items.length;
|
||||
|
||||
const bySeverity = {
|
||||
low: 0,
|
||||
medium: 0,
|
||||
high: 0,
|
||||
critical: 0
|
||||
};
|
||||
|
||||
const byType: Record<string, number> = {};
|
||||
|
||||
let totalFrequency = 0;
|
||||
|
||||
for (const item of items) {
|
||||
bySeverity[item.severity]++;
|
||||
byType[item.exceptionType] = (byType[item.exceptionType] || 0) + 1;
|
||||
totalFrequency += item.frequency;
|
||||
}
|
||||
|
||||
const mostFrequent = [...items].sort((a, b) => b.frequency - a.frequency).slice(0, 10);
|
||||
const recentlyUpdated = [...items].sort((a, b) => b.lastUpdated.getTime() - a.lastUpdated.getTime()).slice(0, 10);
|
||||
|
||||
const averageFrequency = totalItems > 0 ? totalFrequency / totalItems : 0;
|
||||
|
||||
return {
|
||||
totalItems,
|
||||
bySeverity,
|
||||
byType,
|
||||
mostFrequent,
|
||||
recentlyUpdated,
|
||||
averageFrequency
|
||||
};
|
||||
}
|
||||
|
||||
// 导入异常知识
|
||||
async importKnowledge(items: Omit<ExceptionKnowledgeItem, 'id' | 'frequency' | 'createdAt' | 'lastUpdated' | 'lastSeen'>[]): Promise<{
|
||||
success: number;
|
||||
failed: number;
|
||||
}> {
|
||||
let success = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const item of items) {
|
||||
try {
|
||||
await this.addKnowledgeItem(item);
|
||||
success++;
|
||||
} catch (error) {
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
return { success, failed };
|
||||
}
|
||||
|
||||
// 导出异常知识
|
||||
exportKnowledge(filters?: {
|
||||
severity?: string;
|
||||
exceptionType?: string;
|
||||
minFrequency?: number;
|
||||
}): ExceptionKnowledgeItem[] {
|
||||
return this.getAllKnowledgeItems(filters);
|
||||
}
|
||||
|
||||
// 生成异常知识报告
|
||||
async generateKnowledgeReport(): Promise<{
|
||||
stats: ExceptionKnowledgeStats;
|
||||
mostCommonExceptions: ExceptionKnowledgeItem[];
|
||||
leastCommonExceptions: ExceptionKnowledgeItem[];
|
||||
recentlyAdded: ExceptionKnowledgeItem[];
|
||||
}> {
|
||||
const items = Array.from(this.knowledgeItems.values());
|
||||
const stats = this.getKnowledgeStats();
|
||||
|
||||
const mostCommonExceptions = [...items].sort((a, b) => b.frequency - a.frequency).slice(0, 20);
|
||||
const leastCommonExceptions = [...items].sort((a, b) => a.frequency - b.frequency).slice(0, 20);
|
||||
const recentlyAdded = [...items].sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()).slice(0, 20);
|
||||
|
||||
return {
|
||||
stats,
|
||||
mostCommonExceptions,
|
||||
leastCommonExceptions,
|
||||
recentlyAdded
|
||||
};
|
||||
}
|
||||
|
||||
// 清理旧的异常知识
|
||||
async cleanupOldKnowledge(days: number = 365): Promise<number> {
|
||||
const cutoffDate = new Date();
|
||||
cutoffDate.setDate(cutoffDate.getDate() - days);
|
||||
|
||||
let removedCount = 0;
|
||||
|
||||
for (const [id, item] of this.knowledgeItems.entries()) {
|
||||
if (item.lastSeen < cutoffDate && item.frequency < 5) {
|
||||
this.knowledgeItems.delete(id);
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedCount > 0) {
|
||||
this.eventBus.publish('exception.knowledge.cleanup', {
|
||||
removedCount,
|
||||
cutoffDate,
|
||||
timestamp: new Date()
|
||||
});
|
||||
}
|
||||
|
||||
return removedCount;
|
||||
}
|
||||
}
|
||||
412
server/src/core/exception/ExceptionMonitor.ts
Normal file
412
server/src/core/exception/ExceptionMonitor.ts
Normal file
@@ -0,0 +1,412 @@
|
||||
import { DomainEventBus } from '../runtime/DomainEventBus';
|
||||
|
||||
// 异常信息
|
||||
export interface ExceptionInfo {
|
||||
id: string;
|
||||
type: string;
|
||||
message: string;
|
||||
stack?: string;
|
||||
service: string;
|
||||
context?: Record<string, any>;
|
||||
severity: 'low' | 'medium' | 'high' | 'critical';
|
||||
status: 'open' | 'processing' | 'resolved' | 'ignored';
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
resolvedAt?: Date;
|
||||
resolvedBy?: string;
|
||||
}
|
||||
|
||||
// 异常统计
|
||||
export interface ExceptionStats {
|
||||
total: number;
|
||||
bySeverity: {
|
||||
low: number;
|
||||
medium: number;
|
||||
high: number;
|
||||
critical: number;
|
||||
};
|
||||
byStatus: {
|
||||
open: number;
|
||||
processing: number;
|
||||
resolved: number;
|
||||
ignored: number;
|
||||
};
|
||||
byService: Record<string, number>;
|
||||
byType: Record<string, number>;
|
||||
averageResolutionTime: number; // 平均解决时间(分钟)
|
||||
last24Hours: number;
|
||||
last7Days: number;
|
||||
}
|
||||
|
||||
// 异常监控
|
||||
export class ExceptionMonitor {
|
||||
private static instance: ExceptionMonitor;
|
||||
private exceptions: Map<string, ExceptionInfo> = new Map();
|
||||
private eventBus: DomainEventBus;
|
||||
private severityThresholds: Record<string, number> = {
|
||||
low: 10,
|
||||
medium: 5,
|
||||
high: 2,
|
||||
critical: 1
|
||||
};
|
||||
|
||||
private constructor() {
|
||||
this.eventBus = DomainEventBus.getInstance();
|
||||
}
|
||||
|
||||
static getInstance(): ExceptionMonitor {
|
||||
if (!ExceptionMonitor.instance) {
|
||||
ExceptionMonitor.instance = new ExceptionMonitor();
|
||||
}
|
||||
return ExceptionMonitor.instance;
|
||||
}
|
||||
|
||||
// 记录异常
|
||||
async recordException(exception: Omit<ExceptionInfo, 'id' | 'status' | 'createdAt' | 'lastUpdated'>): Promise<ExceptionInfo> {
|
||||
const id = `exception_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newException: ExceptionInfo = {
|
||||
...exception,
|
||||
id,
|
||||
status: 'open',
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.exceptions.set(id, newException);
|
||||
this.eventBus.publish('exception.recorded', newException);
|
||||
|
||||
// 检查是否需要触发告警
|
||||
await this.checkAlertThreshold(newException);
|
||||
|
||||
return newException;
|
||||
}
|
||||
|
||||
// 获取异常信息
|
||||
getException(exceptionId: string): ExceptionInfo | undefined {
|
||||
return this.exceptions.get(exceptionId);
|
||||
}
|
||||
|
||||
// 获取所有异常
|
||||
getAllExceptions(filters?: {
|
||||
severity?: string;
|
||||
status?: string;
|
||||
service?: string;
|
||||
type?: string;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
}): ExceptionInfo[] {
|
||||
let result = Array.from(this.exceptions.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.severity) {
|
||||
result = result.filter(e => e.severity === filters.severity);
|
||||
}
|
||||
|
||||
if (filters.status) {
|
||||
result = result.filter(e => e.status === filters.status);
|
||||
}
|
||||
|
||||
if (filters.service) {
|
||||
result = result.filter(e => e.service === filters.service);
|
||||
}
|
||||
|
||||
if (filters.type) {
|
||||
result = result.filter(e => e.type === filters.type);
|
||||
}
|
||||
|
||||
if (filters.startDate) {
|
||||
result = result.filter(e => e.createdAt >= filters.startDate!);
|
||||
}
|
||||
|
||||
if (filters.endDate) {
|
||||
result = result.filter(e => e.createdAt <= filters.endDate!);
|
||||
}
|
||||
}
|
||||
|
||||
return result.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
||||
}
|
||||
|
||||
// 更新异常状态
|
||||
async updateExceptionStatus(exceptionId: string, status: 'open' | 'processing' | 'resolved' | 'ignored', resolvedBy?: string): Promise<ExceptionInfo | null> {
|
||||
const exception = this.exceptions.get(exceptionId);
|
||||
if (!exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedException = {
|
||||
...exception,
|
||||
status,
|
||||
lastUpdated: new Date(),
|
||||
resolvedAt: status === 'resolved' ? new Date() : exception.resolvedAt,
|
||||
resolvedBy: status === 'resolved' ? resolvedBy : exception.resolvedBy
|
||||
};
|
||||
|
||||
this.exceptions.set(exceptionId, updatedException);
|
||||
this.eventBus.publish('exception.status.updated', updatedException);
|
||||
return updatedException;
|
||||
}
|
||||
|
||||
// 更新异常信息
|
||||
async updateException(exceptionId: string, updates: Partial<ExceptionInfo>): Promise<ExceptionInfo | null> {
|
||||
const exception = this.exceptions.get(exceptionId);
|
||||
if (!exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedException = {
|
||||
...exception,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.exceptions.set(exceptionId, updatedException);
|
||||
this.eventBus.publish('exception.updated', updatedException);
|
||||
return updatedException;
|
||||
}
|
||||
|
||||
// 检查告警阈值
|
||||
private async checkAlertThreshold(exception: ExceptionInfo): Promise<void> {
|
||||
const threshold = this.severityThresholds[exception.severity];
|
||||
if (!threshold) return;
|
||||
|
||||
// 检查过去24小时内相同类型的异常数量
|
||||
const last24Hours = new Date();
|
||||
last24Hours.setHours(last24Hours.getHours() - 24);
|
||||
|
||||
const similarExceptions = Array.from(this.exceptions.values()).filter(e =>
|
||||
e.type === exception.type &&
|
||||
e.service === exception.service &&
|
||||
e.createdAt >= last24Hours
|
||||
);
|
||||
|
||||
if (similarExceptions.length >= threshold) {
|
||||
this.eventBus.publish('exception.alert', {
|
||||
exception,
|
||||
count: similarExceptions.length,
|
||||
threshold,
|
||||
timestamp: new Date()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 获取异常统计
|
||||
getExceptionStats(): ExceptionStats {
|
||||
const exceptions = Array.from(this.exceptions.values());
|
||||
const total = exceptions.length;
|
||||
|
||||
const bySeverity = {
|
||||
low: 0,
|
||||
medium: 0,
|
||||
high: 0,
|
||||
critical: 0
|
||||
};
|
||||
|
||||
const byStatus = {
|
||||
open: 0,
|
||||
processing: 0,
|
||||
resolved: 0,
|
||||
ignored: 0
|
||||
};
|
||||
|
||||
const byService: Record<string, number> = {};
|
||||
const byType: Record<string, number> = {};
|
||||
|
||||
let totalResolutionTime = 0;
|
||||
let resolvedExceptions = 0;
|
||||
|
||||
const last24Hours = new Date();
|
||||
last24Hours.setHours(last24Hours.getHours() - 24);
|
||||
|
||||
const last7Days = new Date();
|
||||
last7Days.setDate(last7Days.getDate() - 7);
|
||||
|
||||
let exceptionsLast24Hours = 0;
|
||||
let exceptionsLast7Days = 0;
|
||||
|
||||
for (const exception of exceptions) {
|
||||
bySeverity[exception.severity]++;
|
||||
byStatus[exception.status]++;
|
||||
|
||||
byService[exception.service] = (byService[exception.service] || 0) + 1;
|
||||
byType[exception.type] = (byType[exception.type] || 0) + 1;
|
||||
|
||||
if (exception.status === 'resolved' && exception.resolvedAt) {
|
||||
const resolutionTime = (exception.resolvedAt.getTime() - exception.createdAt.getTime()) / (1000 * 60); // 转换为分钟
|
||||
totalResolutionTime += resolutionTime;
|
||||
resolvedExceptions++;
|
||||
}
|
||||
|
||||
if (exception.createdAt >= last24Hours) {
|
||||
exceptionsLast24Hours++;
|
||||
}
|
||||
|
||||
if (exception.createdAt >= last7Days) {
|
||||
exceptionsLast7Days++;
|
||||
}
|
||||
}
|
||||
|
||||
const averageResolutionTime = resolvedExceptions > 0
|
||||
? totalResolutionTime / resolvedExceptions
|
||||
: 0;
|
||||
|
||||
return {
|
||||
total,
|
||||
bySeverity,
|
||||
byStatus,
|
||||
byService,
|
||||
byType,
|
||||
averageResolutionTime,
|
||||
last24Hours: exceptionsLast24Hours,
|
||||
last7Days: exceptionsLast7Days
|
||||
};
|
||||
}
|
||||
|
||||
// 获取服务异常统计
|
||||
getServiceExceptionStats(service: string): ExceptionStats {
|
||||
const serviceExceptions = Array.from(this.exceptions.values()).filter(e => e.service === service);
|
||||
|
||||
const total = serviceExceptions.length;
|
||||
|
||||
const bySeverity = {
|
||||
low: 0,
|
||||
medium: 0,
|
||||
high: 0,
|
||||
critical: 0
|
||||
};
|
||||
|
||||
const byStatus = {
|
||||
open: 0,
|
||||
processing: 0,
|
||||
resolved: 0,
|
||||
ignored: 0
|
||||
};
|
||||
|
||||
const byType: Record<string, number> = {};
|
||||
|
||||
let totalResolutionTime = 0;
|
||||
let resolvedExceptions = 0;
|
||||
|
||||
const last24Hours = new Date();
|
||||
last24Hours.setHours(last24Hours.getHours() - 24);
|
||||
|
||||
const last7Days = new Date();
|
||||
last7Days.setDate(last7Days.getDate() - 7);
|
||||
|
||||
let exceptionsLast24Hours = 0;
|
||||
let exceptionsLast7Days = 0;
|
||||
|
||||
for (const exception of serviceExceptions) {
|
||||
bySeverity[exception.severity]++;
|
||||
byStatus[exception.status]++;
|
||||
|
||||
byType[exception.type] = (byType[exception.type] || 0) + 1;
|
||||
|
||||
if (exception.status === 'resolved' && exception.resolvedAt) {
|
||||
const resolutionTime = (exception.resolvedAt.getTime() - exception.createdAt.getTime()) / (1000 * 60); // 转换为分钟
|
||||
totalResolutionTime += resolutionTime;
|
||||
resolvedExceptions++;
|
||||
}
|
||||
|
||||
if (exception.createdAt >= last24Hours) {
|
||||
exceptionsLast24Hours++;
|
||||
}
|
||||
|
||||
if (exception.createdAt >= last7Days) {
|
||||
exceptionsLast7Days++;
|
||||
}
|
||||
}
|
||||
|
||||
const averageResolutionTime = resolvedExceptions > 0
|
||||
? totalResolutionTime / resolvedExceptions
|
||||
: 0;
|
||||
|
||||
return {
|
||||
total,
|
||||
bySeverity,
|
||||
byStatus,
|
||||
byService: { [service]: total },
|
||||
byType,
|
||||
averageResolutionTime,
|
||||
last24Hours: exceptionsLast24Hours,
|
||||
last7Days: exceptionsLast7Days
|
||||
};
|
||||
}
|
||||
|
||||
// 清理旧异常
|
||||
async cleanupOldExceptions(days: number = 30): Promise<number> {
|
||||
const cutoffDate = new Date();
|
||||
cutoffDate.setDate(cutoffDate.getDate() - days);
|
||||
|
||||
let removedCount = 0;
|
||||
|
||||
for (const [id, exception] of this.exceptions.entries()) {
|
||||
if (exception.createdAt < cutoffDate && exception.status === 'resolved') {
|
||||
this.exceptions.delete(id);
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedCount > 0) {
|
||||
this.eventBus.publish('exception.cleanup', {
|
||||
removedCount,
|
||||
cutoffDate,
|
||||
timestamp: new Date()
|
||||
});
|
||||
}
|
||||
|
||||
return removedCount;
|
||||
}
|
||||
|
||||
// 生成异常报告
|
||||
async generateExceptionReport(startDate: Date, endDate: Date): Promise<{
|
||||
summary: ExceptionStats;
|
||||
topExceptions: ExceptionInfo[];
|
||||
serviceStats: Record<string, ExceptionStats>;
|
||||
}> {
|
||||
const filteredExceptions = Array.from(this.exceptions.values()).filter(
|
||||
e => e.createdAt >= startDate && e.createdAt <= endDate
|
||||
);
|
||||
|
||||
// 按频率排序的异常类型
|
||||
const typeFrequency: Record<string, number> = {};
|
||||
for (const exception of filteredExceptions) {
|
||||
typeFrequency[exception.type] = (typeFrequency[exception.type] || 0) + 1;
|
||||
}
|
||||
|
||||
const sortedTypes = Object.entries(typeFrequency)
|
||||
.sort(([, a], [, b]) => b - a)
|
||||
.slice(0, 10)
|
||||
.map(([type]) => type);
|
||||
|
||||
const topExceptions = filteredExceptions
|
||||
.filter(e => sortedTypes.includes(e.type))
|
||||
.slice(0, 20);
|
||||
|
||||
// 按服务分组的统计
|
||||
const serviceStats: Record<string, ExceptionStats> = {};
|
||||
const services = Array.from(new Set(filteredExceptions.map(e => e.service)));
|
||||
for (const service of services) {
|
||||
serviceStats[service] = this.getServiceExceptionStats(service);
|
||||
}
|
||||
|
||||
return {
|
||||
summary: this.getExceptionStats(),
|
||||
topExceptions,
|
||||
serviceStats
|
||||
};
|
||||
}
|
||||
|
||||
// 设置严重性阈值
|
||||
setSeverityThresholds(thresholds: Record<string, number>): void {
|
||||
this.severityThresholds = {
|
||||
...this.severityThresholds,
|
||||
...thresholds
|
||||
};
|
||||
}
|
||||
|
||||
// 获取严重性阈值
|
||||
getSeverityThresholds(): Record<string, number> {
|
||||
return { ...this.severityThresholds };
|
||||
}
|
||||
}
|
||||
398
server/src/core/exception/IntelligentExceptionHandler.ts
Normal file
398
server/src/core/exception/IntelligentExceptionHandler.ts
Normal file
@@ -0,0 +1,398 @@
|
||||
import { DomainEventBus } from '../runtime/DomainEventBus';
|
||||
import { ExceptionInfo } from './ExceptionMonitor';
|
||||
|
||||
// 异常处理策略
|
||||
export interface ExceptionHandlingStrategy {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
exceptionType: string;
|
||||
severity: 'low' | 'medium' | 'high' | 'critical';
|
||||
actions: ExceptionAction[];
|
||||
enabled: boolean;
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
}
|
||||
|
||||
// 异常处理动作
|
||||
export interface ExceptionAction {
|
||||
type: 'retry' | 'fallback' | 'alert' | 'auto-fix' | 'escalate';
|
||||
parameters?: Record<string, any>;
|
||||
order: number;
|
||||
}
|
||||
|
||||
// 异常处理结果
|
||||
export interface ExceptionHandlingResult {
|
||||
id: string;
|
||||
exceptionId: string;
|
||||
strategyId: string;
|
||||
actions: {
|
||||
type: string;
|
||||
success: boolean;
|
||||
message: string;
|
||||
timestamp: Date;
|
||||
}[];
|
||||
overallStatus: 'success' | 'partial' | 'failure';
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
// 智能异常处理
|
||||
export class IntelligentExceptionHandler {
|
||||
private static instance: IntelligentExceptionHandler;
|
||||
private strategies: Map<string, ExceptionHandlingStrategy> = new Map();
|
||||
private handlingResults: Map<string, ExceptionHandlingResult> = new Map();
|
||||
private eventBus: DomainEventBus;
|
||||
|
||||
private constructor() {
|
||||
this.eventBus = DomainEventBus.getInstance();
|
||||
}
|
||||
|
||||
static getInstance(): IntelligentExceptionHandler {
|
||||
if (!IntelligentExceptionHandler.instance) {
|
||||
IntelligentExceptionHandler.instance = new IntelligentExceptionHandler();
|
||||
}
|
||||
return IntelligentExceptionHandler.instance;
|
||||
}
|
||||
|
||||
// 创建异常处理策略
|
||||
async createStrategy(strategy: Omit<ExceptionHandlingStrategy, 'id' | 'createdAt' | 'lastUpdated'>): Promise<ExceptionHandlingStrategy> {
|
||||
const id = `strategy_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newStrategy: ExceptionHandlingStrategy = {
|
||||
...strategy,
|
||||
id,
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.strategies.set(id, newStrategy);
|
||||
this.eventBus.publish('exception.strategy.created', newStrategy);
|
||||
return newStrategy;
|
||||
}
|
||||
|
||||
// 获取异常处理策略
|
||||
getStrategy(strategyId: string): ExceptionHandlingStrategy | undefined {
|
||||
return this.strategies.get(strategyId);
|
||||
}
|
||||
|
||||
// 获取所有异常处理策略
|
||||
getAllStrategies(filters?: {
|
||||
exceptionType?: string;
|
||||
severity?: string;
|
||||
enabled?: boolean;
|
||||
}): ExceptionHandlingStrategy[] {
|
||||
let result = Array.from(this.strategies.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.exceptionType) {
|
||||
result = result.filter(s => s.exceptionType === filters.exceptionType);
|
||||
}
|
||||
|
||||
if (filters.severity) {
|
||||
result = result.filter(s => s.severity === filters.severity);
|
||||
}
|
||||
|
||||
if (filters.enabled !== undefined) {
|
||||
result = result.filter(s => s.enabled === filters.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 更新异常处理策略
|
||||
async updateStrategy(strategyId: string, updates: Partial<ExceptionHandlingStrategy>): Promise<ExceptionHandlingStrategy | null> {
|
||||
const strategy = this.strategies.get(strategyId);
|
||||
if (!strategy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedStrategy = {
|
||||
...strategy,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.strategies.set(strategyId, updatedStrategy);
|
||||
this.eventBus.publish('exception.strategy.updated', updatedStrategy);
|
||||
return updatedStrategy;
|
||||
}
|
||||
|
||||
// 启用/禁用异常处理策略
|
||||
async toggleStrategy(strategyId: string, enabled: boolean): Promise<boolean> {
|
||||
const strategy = this.strategies.get(strategyId);
|
||||
if (!strategy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strategy.enabled = enabled;
|
||||
strategy.lastUpdated = new Date();
|
||||
this.strategies.set(strategyId, strategy);
|
||||
this.eventBus.publish('exception.strategy.toggled', strategy);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理异常
|
||||
async handleException(exception: ExceptionInfo): Promise<ExceptionHandlingResult> {
|
||||
// 查找匹配的策略
|
||||
const strategies = this.getAllStrategies({
|
||||
exceptionType: exception.type,
|
||||
enabled: true
|
||||
});
|
||||
|
||||
// 按严重性排序,选择最匹配的策略
|
||||
strategies.sort((a, b) => {
|
||||
const severityOrder = { critical: 4, high: 3, medium: 2, low: 1 };
|
||||
return severityOrder[b.severity] - severityOrder[a.severity];
|
||||
});
|
||||
|
||||
const strategy = strategies[0];
|
||||
const actions: ExceptionHandlingResult['actions'] = [];
|
||||
let overallStatus: 'success' | 'partial' | 'failure' = 'failure';
|
||||
|
||||
if (strategy) {
|
||||
// 按顺序执行策略中的动作
|
||||
const sortedActions = [...strategy.actions].sort((a, b) => a.order - b.order);
|
||||
let successCount = 0;
|
||||
|
||||
for (const action of sortedActions) {
|
||||
const result = await this.executeAction(action, exception);
|
||||
actions.push(result);
|
||||
if (result.success) {
|
||||
successCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (successCount === sortedActions.length) {
|
||||
overallStatus = 'success';
|
||||
} else if (successCount > 0) {
|
||||
overallStatus = 'partial';
|
||||
}
|
||||
} else {
|
||||
// 默认动作:告警
|
||||
const result = await this.executeAction({
|
||||
type: 'alert',
|
||||
order: 1
|
||||
}, exception);
|
||||
actions.push(result);
|
||||
overallStatus = result.success ? 'success' : 'failure';
|
||||
}
|
||||
|
||||
const handlingResult: ExceptionHandlingResult = {
|
||||
id: `result_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||
exceptionId: exception.id,
|
||||
strategyId: strategy?.id || 'default',
|
||||
actions,
|
||||
overallStatus,
|
||||
timestamp: new Date()
|
||||
};
|
||||
|
||||
this.handlingResults.set(handlingResult.id, handlingResult);
|
||||
this.eventBus.publish('exception.handled', handlingResult);
|
||||
return handlingResult;
|
||||
}
|
||||
|
||||
// 执行异常处理动作
|
||||
private async executeAction(action: ExceptionAction, exception: ExceptionInfo): Promise<ExceptionHandlingResult['actions'][0]> {
|
||||
try {
|
||||
switch (action.type) {
|
||||
case 'retry':
|
||||
return await this.executeRetryAction(action, exception);
|
||||
case 'fallback':
|
||||
return await this.executeFallbackAction(action, exception);
|
||||
case 'alert':
|
||||
return await this.executeAlertAction(action, exception);
|
||||
case 'auto-fix':
|
||||
return await this.executeAutoFixAction(action, exception);
|
||||
case 'escalate':
|
||||
return await this.executeEscalateAction(action, exception);
|
||||
default:
|
||||
return {
|
||||
type: action.type,
|
||||
success: false,
|
||||
message: `Unknown action type: ${action.type}`,
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
type: action.type,
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : 'Unknown error',
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 执行重试动作
|
||||
private async executeRetryAction(action: ExceptionAction, exception: ExceptionInfo): Promise<ExceptionHandlingResult['actions'][0]> {
|
||||
const maxRetries = action.parameters?.maxRetries || 3;
|
||||
const delayMs = action.parameters?.delayMs || 1000;
|
||||
|
||||
for (let i = 0; i < maxRetries; i++) {
|
||||
try {
|
||||
// 这里应该有实际的重试逻辑
|
||||
// 暂时模拟重试
|
||||
await new Promise(resolve => setTimeout(resolve, delayMs));
|
||||
|
||||
const success = Math.random() > 0.3; // 70% 成功率
|
||||
if (success) {
|
||||
return {
|
||||
type: 'retry',
|
||||
success: true,
|
||||
message: `Successfully retried after ${i + 1} attempt(s)`,
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
// 重试失败,继续下一次
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'retry',
|
||||
success: false,
|
||||
message: `Failed after ${maxRetries} attempts`,
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
|
||||
// 执行回退动作
|
||||
private async executeFallbackAction(action: ExceptionAction, exception: ExceptionInfo): Promise<ExceptionHandlingResult['actions'][0]> {
|
||||
// 这里应该有实际的回退逻辑
|
||||
// 暂时模拟回退
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
|
||||
return {
|
||||
type: 'fallback',
|
||||
success: true,
|
||||
message: 'Fallback executed successfully',
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
|
||||
// 执行告警动作
|
||||
private async executeAlertAction(action: ExceptionAction, exception: ExceptionInfo): Promise<ExceptionHandlingResult['actions'][0]> {
|
||||
// 这里应该有实际的告警逻辑
|
||||
// 暂时模拟告警
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
|
||||
this.eventBus.publish('exception.alert', {
|
||||
exception,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
return {
|
||||
type: 'alert',
|
||||
success: true,
|
||||
message: 'Alert sent successfully',
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
|
||||
// 执行自动修复动作
|
||||
private async executeAutoFixAction(action: ExceptionAction, exception: ExceptionInfo): Promise<ExceptionHandlingResult['actions'][0]> {
|
||||
// 这里应该有实际的自动修复逻辑
|
||||
// 暂时模拟自动修复
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
const success = Math.random() > 0.2; // 80% 成功率
|
||||
return {
|
||||
type: 'auto-fix',
|
||||
success,
|
||||
message: success ? 'Auto-fix executed successfully' : 'Auto-fix failed',
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
|
||||
// 执行升级动作
|
||||
private async executeEscalateAction(action: ExceptionAction, exception: ExceptionInfo): Promise<ExceptionHandlingResult['actions'][0]> {
|
||||
// 这里应该有实际的升级逻辑
|
||||
// 暂时模拟升级
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
|
||||
this.eventBus.publish('exception.escalated', {
|
||||
exception,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
return {
|
||||
type: 'escalate',
|
||||
success: true,
|
||||
message: 'Exception escalated successfully',
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
|
||||
// 获取异常处理结果
|
||||
getHandlingResult(resultId: string): ExceptionHandlingResult | undefined {
|
||||
return this.handlingResults.get(resultId);
|
||||
}
|
||||
|
||||
// 获取异常的处理结果
|
||||
getExceptionHandlingResults(exceptionId: string): ExceptionHandlingResult[] {
|
||||
return Array.from(this.handlingResults.values()).filter(r => r.exceptionId === exceptionId);
|
||||
}
|
||||
|
||||
// 获取策略的处理结果
|
||||
getStrategyHandlingResults(strategyId: string): ExceptionHandlingResult[] {
|
||||
return Array.from(this.handlingResults.values()).filter(r => r.strategyId === strategyId);
|
||||
}
|
||||
|
||||
// 批量处理异常
|
||||
async batchHandleExceptions(exceptionIds: string[], exceptionMonitor: any): Promise<ExceptionHandlingResult[]> {
|
||||
const results: ExceptionHandlingResult[] = [];
|
||||
|
||||
for (const exceptionId of exceptionIds) {
|
||||
const exception = exceptionMonitor.getException(exceptionId);
|
||||
if (exception) {
|
||||
const result = await this.handleException(exception);
|
||||
results.push(result);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// 生成异常处理报告
|
||||
async generateHandlingReport(startDate: Date, endDate: Date): Promise<{
|
||||
summary: {
|
||||
totalExceptions: number;
|
||||
successfullyHandled: number;
|
||||
partiallyHandled: number;
|
||||
failedHandled: number;
|
||||
mostUsedStrategies: string[];
|
||||
};
|
||||
details: ExceptionHandlingResult[];
|
||||
}> {
|
||||
const filteredResults = Array.from(this.handlingResults.values()).filter(
|
||||
r => r.timestamp >= startDate && r.timestamp <= endDate
|
||||
);
|
||||
|
||||
const successfullyHandled = filteredResults.filter(r => r.overallStatus === 'success').length;
|
||||
const partiallyHandled = filteredResults.filter(r => r.overallStatus === 'partial').length;
|
||||
const failedHandled = filteredResults.filter(r => r.overallStatus === 'failure').length;
|
||||
|
||||
// 统计最常用的策略
|
||||
const strategyUsage: Record<string, number> = {};
|
||||
for (const result of filteredResults) {
|
||||
strategyUsage[result.strategyId] = (strategyUsage[result.strategyId] || 0) + 1;
|
||||
}
|
||||
|
||||
const mostUsedStrategies = Object.entries(strategyUsage)
|
||||
.sort(([, a], [, b]) => b - a)
|
||||
.slice(0, 5)
|
||||
.map(([strategyId]) => strategyId);
|
||||
|
||||
return {
|
||||
summary: {
|
||||
totalExceptions: filteredResults.length,
|
||||
successfullyHandled,
|
||||
partiallyHandled,
|
||||
failedHandled,
|
||||
mostUsedStrategies
|
||||
},
|
||||
details: filteredResults
|
||||
};
|
||||
}
|
||||
}
|
||||
272
server/src/core/governance/DeveloperPlatform.ts
Normal file
272
server/src/core/governance/DeveloperPlatform.ts
Normal file
@@ -0,0 +1,272 @@
|
||||
import { DomainEventBus } from '../runtime/DomainEventBus';
|
||||
import { ServiceRegistry } from '../orchestrator/ServiceRegistry';
|
||||
|
||||
// 开发者信息
|
||||
export interface Developer {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
apiKey: string;
|
||||
createdAt: Date;
|
||||
lastActive: Date;
|
||||
status: 'active' | 'inactive' | 'suspended';
|
||||
permissions: string[];
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
// 插件信息
|
||||
export interface Plugin {
|
||||
id: string;
|
||||
name: string;
|
||||
version: string;
|
||||
description: string;
|
||||
developerId: string;
|
||||
type: 'adapter' | 'service' | 'UI' | 'integration';
|
||||
status: 'pending' | 'approved' | 'rejected' | 'published';
|
||||
dependencies: string[];
|
||||
entryPoint: string;
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
// API密钥
|
||||
export interface ApiKey {
|
||||
id: string;
|
||||
developerId: string;
|
||||
key: string;
|
||||
name: string;
|
||||
permissions: string[];
|
||||
createdAt: Date;
|
||||
expiresAt: Date;
|
||||
status: 'active' | 'revoked' | 'expired';
|
||||
}
|
||||
|
||||
// 开发者平台
|
||||
export class DeveloperPlatform {
|
||||
private static instance: DeveloperPlatform;
|
||||
private developers: Map<string, Developer> = new Map();
|
||||
private plugins: Map<string, Plugin> = new Map();
|
||||
private apiKeys: Map<string, ApiKey> = new Map();
|
||||
private serviceRegistry: ServiceRegistry;
|
||||
private eventBus: DomainEventBus;
|
||||
|
||||
private constructor() {
|
||||
this.serviceRegistry = ServiceRegistry.getInstance();
|
||||
this.eventBus = DomainEventBus.getInstance();
|
||||
}
|
||||
|
||||
static getInstance(): DeveloperPlatform {
|
||||
if (!DeveloperPlatform.instance) {
|
||||
DeveloperPlatform.instance = new DeveloperPlatform();
|
||||
}
|
||||
return DeveloperPlatform.instance;
|
||||
}
|
||||
|
||||
// 注册开发者
|
||||
async registerDeveloper(developer: Omit<Developer, 'id' | 'createdAt' | 'lastActive' | 'apiKey'>): Promise<Developer> {
|
||||
const id = `dev_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
const apiKey = this.generateApiKey();
|
||||
|
||||
const newDeveloper: Developer = {
|
||||
...developer,
|
||||
id,
|
||||
apiKey,
|
||||
createdAt: new Date(),
|
||||
lastActive: new Date()
|
||||
};
|
||||
|
||||
this.developers.set(id, newDeveloper);
|
||||
this.eventBus.publish('developer.registered', newDeveloper);
|
||||
return newDeveloper;
|
||||
}
|
||||
|
||||
// 获取开发者信息
|
||||
getDeveloper(developerId: string): Developer | undefined {
|
||||
return this.developers.get(developerId);
|
||||
}
|
||||
|
||||
// 获取所有开发者
|
||||
getAllDevelopers(): Developer[] {
|
||||
return Array.from(this.developers.values());
|
||||
}
|
||||
|
||||
// 更新开发者信息
|
||||
async updateDeveloper(developerId: string, updates: Partial<Developer>): Promise<Developer | null> {
|
||||
const developer = this.developers.get(developerId);
|
||||
if (!developer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedDeveloper = {
|
||||
...developer,
|
||||
...updates,
|
||||
lastActive: new Date()
|
||||
};
|
||||
|
||||
this.developers.set(developerId, updatedDeveloper);
|
||||
this.eventBus.publish('developer.updated', updatedDeveloper);
|
||||
return updatedDeveloper;
|
||||
}
|
||||
|
||||
// 停用开发者
|
||||
async deactivateDeveloper(developerId: string): Promise<boolean> {
|
||||
const developer = this.developers.get(developerId);
|
||||
if (!developer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
developer.status = 'inactive';
|
||||
developer.lastActive = new Date();
|
||||
this.developers.set(developerId, developer);
|
||||
this.eventBus.publish('developer.deactivated', developer);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 注册插件
|
||||
async registerPlugin(plugin: Omit<Plugin, 'id' | 'createdAt' | 'lastUpdated' | 'status'>): Promise<Plugin> {
|
||||
const id = `plugin_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newPlugin: Plugin = {
|
||||
...plugin,
|
||||
id,
|
||||
status: 'pending',
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.plugins.set(id, newPlugin);
|
||||
this.eventBus.publish('plugin.registered', newPlugin);
|
||||
return newPlugin;
|
||||
}
|
||||
|
||||
// 获取插件信息
|
||||
getPlugin(pluginId: string): Plugin | undefined {
|
||||
return this.plugins.get(pluginId);
|
||||
}
|
||||
|
||||
// 获取所有插件
|
||||
getAllPlugins(): Plugin[] {
|
||||
return Array.from(this.plugins.values());
|
||||
}
|
||||
|
||||
// 获取开发者的插件
|
||||
getDeveloperPlugins(developerId: string): Plugin[] {
|
||||
return Array.from(this.plugins.values()).filter(p => p.developerId === developerId);
|
||||
}
|
||||
|
||||
// 审核插件
|
||||
async reviewPlugin(pluginId: string, status: 'approved' | 'rejected', reason?: string): Promise<Plugin | null> {
|
||||
const plugin = this.plugins.get(pluginId);
|
||||
if (!plugin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
plugin.status = status;
|
||||
plugin.lastUpdated = new Date();
|
||||
if (reason) {
|
||||
plugin.metadata = {
|
||||
...plugin.metadata,
|
||||
reviewReason: reason
|
||||
};
|
||||
}
|
||||
|
||||
this.plugins.set(pluginId, plugin);
|
||||
this.eventBus.publish('plugin.reviewed', plugin);
|
||||
|
||||
if (status === 'approved') {
|
||||
// 发布插件
|
||||
plugin.status = 'published';
|
||||
this.eventBus.publish('plugin.published', plugin);
|
||||
}
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
// 生成API密钥
|
||||
async generateApiKey(developerId: string, name: string, permissions: string[], expiresInDays: number = 365): Promise<ApiKey> {
|
||||
const developer = this.developers.get(developerId);
|
||||
if (!developer) {
|
||||
throw new Error('Developer not found');
|
||||
}
|
||||
|
||||
const id = `apikey_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
const key = this.generateApiKey();
|
||||
const expiresAt = new Date();
|
||||
expiresAt.setDate(expiresAt.getDate() + expiresInDays);
|
||||
|
||||
const apiKey: ApiKey = {
|
||||
id,
|
||||
developerId,
|
||||
key,
|
||||
name,
|
||||
permissions,
|
||||
createdAt: new Date(),
|
||||
expiresAt,
|
||||
status: 'active'
|
||||
};
|
||||
|
||||
this.apiKeys.set(id, apiKey);
|
||||
this.eventBus.publish('apiKey.created', apiKey);
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
// 验证API密钥
|
||||
validateApiKey(apiKey: string): ApiKey | null {
|
||||
const key = Array.from(this.apiKeys.values()).find(k => k.key === apiKey && k.status === 'active' && k.expiresAt > new Date());
|
||||
return key || null;
|
||||
}
|
||||
|
||||
// 撤销API密钥
|
||||
async revokeApiKey(apiKeyId: string): Promise<boolean> {
|
||||
const apiKey = this.apiKeys.get(apiKeyId);
|
||||
if (!apiKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
apiKey.status = 'revoked';
|
||||
this.apiKeys.set(apiKeyId, apiKey);
|
||||
this.eventBus.publish('apiKey.revoked', apiKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 获取开发者的API密钥
|
||||
getDeveloperApiKeys(developerId: string): ApiKey[] {
|
||||
return Array.from(this.apiKeys.values()).filter(k => k.developerId === developerId);
|
||||
}
|
||||
|
||||
// 生成API密钥
|
||||
private generateApiKey(): string {
|
||||
return `sk_${Math.random().toString(36).substr(2, 32)}`;
|
||||
}
|
||||
|
||||
// 导入插件
|
||||
async importPlugin(pluginData: any): Promise<Plugin> {
|
||||
// 这里应该有插件导入逻辑
|
||||
// 暂时返回一个模拟的插件
|
||||
return this.registerPlugin({
|
||||
name: pluginData.name,
|
||||
version: pluginData.version,
|
||||
description: pluginData.description,
|
||||
developerId: pluginData.developerId,
|
||||
type: pluginData.type || 'service',
|
||||
dependencies: pluginData.dependencies || [],
|
||||
entryPoint: pluginData.entryPoint
|
||||
});
|
||||
}
|
||||
|
||||
// 导出插件
|
||||
async exportPlugin(pluginId: string): Promise<any> {
|
||||
const plugin = this.plugins.get(pluginId);
|
||||
if (!plugin) {
|
||||
throw new Error('Plugin not found');
|
||||
}
|
||||
|
||||
// 这里应该有插件导出逻辑
|
||||
// 暂时返回插件信息
|
||||
return {
|
||||
...plugin,
|
||||
developer: this.developers.get(plugin.developerId)
|
||||
};
|
||||
}
|
||||
}
|
||||
361
server/src/core/governance/ServiceGovernance.ts
Normal file
361
server/src/core/governance/ServiceGovernance.ts
Normal file
@@ -0,0 +1,361 @@
|
||||
import { DomainEventBus } from '../runtime/DomainEventBus';
|
||||
import { ServiceRegistry } from '../orchestrator/ServiceRegistry';
|
||||
import { ServiceOrchestrator } from '../orchestrator/ServiceOrchestrator';
|
||||
|
||||
// 服务治理规则
|
||||
export interface GovernanceRule {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
type: 'performance' | 'security' | 'compliance' | 'availability';
|
||||
severity: 'low' | 'medium' | 'high' | 'critical';
|
||||
condition: string; // 规则条件
|
||||
action: 'alert' | 'block' | 'auto-fix';
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
// 服务治理事件
|
||||
export interface GovernanceEvent {
|
||||
id: string;
|
||||
serviceId: string;
|
||||
ruleId: string;
|
||||
severity: 'low' | 'medium' | 'high' | 'critical';
|
||||
message: string;
|
||||
timestamp: Date;
|
||||
status: 'open' | 'resolved' | 'ignored';
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
// 服务配额
|
||||
export interface ServiceQuota {
|
||||
serviceId: string;
|
||||
maxRequestsPerSecond: number;
|
||||
maxConcurrentRequests: number;
|
||||
maxMemoryUsage: number; // MB
|
||||
maxCpuUsage: number; // %
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
}
|
||||
|
||||
// 服务治理
|
||||
export class ServiceGovernance {
|
||||
private static instance: ServiceGovernance;
|
||||
private rules: Map<string, GovernanceRule> = new Map();
|
||||
private events: Map<string, GovernanceEvent> = new Map();
|
||||
private quotas: Map<string, ServiceQuota> = new Map();
|
||||
private serviceRegistry: ServiceRegistry;
|
||||
private serviceOrchestrator: ServiceOrchestrator;
|
||||
private eventBus: DomainEventBus;
|
||||
|
||||
private constructor() {
|
||||
this.serviceRegistry = ServiceRegistry.getInstance();
|
||||
this.serviceOrchestrator = ServiceOrchestrator.getInstance();
|
||||
this.eventBus = DomainEventBus.getInstance();
|
||||
}
|
||||
|
||||
static getInstance(): ServiceGovernance {
|
||||
if (!ServiceGovernance.instance) {
|
||||
ServiceGovernance.instance = new ServiceGovernance();
|
||||
}
|
||||
return ServiceGovernance.instance;
|
||||
}
|
||||
|
||||
// 创建治理规则
|
||||
async createRule(rule: Omit<GovernanceRule, 'id' | 'createdAt' | 'lastUpdated'>): Promise<GovernanceRule> {
|
||||
const id = `rule_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newRule: GovernanceRule = {
|
||||
...rule,
|
||||
id,
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.rules.set(id, newRule);
|
||||
this.eventBus.publish('governance.rule.created', newRule);
|
||||
return newRule;
|
||||
}
|
||||
|
||||
// 获取规则信息
|
||||
getRule(ruleId: string): GovernanceRule | undefined {
|
||||
return this.rules.get(ruleId);
|
||||
}
|
||||
|
||||
// 获取所有规则
|
||||
getAllRules(filters?: {
|
||||
type?: string;
|
||||
severity?: string;
|
||||
enabled?: boolean;
|
||||
}): GovernanceRule[] {
|
||||
let result = Array.from(this.rules.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.type) {
|
||||
result = result.filter(r => r.type === filters.type);
|
||||
}
|
||||
|
||||
if (filters.severity) {
|
||||
result = result.filter(r => r.severity === filters.severity);
|
||||
}
|
||||
|
||||
if (filters.enabled !== undefined) {
|
||||
result = result.filter(r => r.enabled === filters.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 更新规则
|
||||
async updateRule(ruleId: string, updates: Partial<GovernanceRule>): Promise<GovernanceRule | null> {
|
||||
const rule = this.rules.get(ruleId);
|
||||
if (!rule) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedRule = {
|
||||
...rule,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.rules.set(ruleId, updatedRule);
|
||||
this.eventBus.publish('governance.rule.updated', updatedRule);
|
||||
return updatedRule;
|
||||
}
|
||||
|
||||
// 启用/禁用规则
|
||||
async toggleRule(ruleId: string, enabled: boolean): Promise<boolean> {
|
||||
const rule = this.rules.get(ruleId);
|
||||
if (!rule) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rule.enabled = enabled;
|
||||
rule.lastUpdated = new Date();
|
||||
this.rules.set(ruleId, rule);
|
||||
this.eventBus.publish('governance.rule.toggled', rule);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 删除规则
|
||||
async deleteRule(ruleId: string): Promise<boolean> {
|
||||
const rule = this.rules.get(ruleId);
|
||||
if (!rule) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.rules.delete(ruleId);
|
||||
this.eventBus.publish('governance.rule.deleted', rule);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 创建治理事件
|
||||
async createEvent(event: Omit<GovernanceEvent, 'id' | 'timestamp' | 'status'>): Promise<GovernanceEvent> {
|
||||
const id = `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newEvent: GovernanceEvent = {
|
||||
...event,
|
||||
id,
|
||||
timestamp: new Date(),
|
||||
status: 'open'
|
||||
};
|
||||
|
||||
this.events.set(id, newEvent);
|
||||
this.eventBus.publish('governance.event.created', newEvent);
|
||||
return newEvent;
|
||||
}
|
||||
|
||||
// 获取事件信息
|
||||
getEvent(eventId: string): GovernanceEvent | undefined {
|
||||
return this.events.get(eventId);
|
||||
}
|
||||
|
||||
// 获取所有事件
|
||||
getAllEvents(filters?: {
|
||||
serviceId?: string;
|
||||
ruleId?: string;
|
||||
severity?: string;
|
||||
status?: string;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
}): GovernanceEvent[] {
|
||||
let result = Array.from(this.events.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.serviceId) {
|
||||
result = result.filter(e => e.serviceId === filters.serviceId);
|
||||
}
|
||||
|
||||
if (filters.ruleId) {
|
||||
result = result.filter(e => e.ruleId === filters.ruleId);
|
||||
}
|
||||
|
||||
if (filters.severity) {
|
||||
result = result.filter(e => e.severity === filters.severity);
|
||||
}
|
||||
|
||||
if (filters.status) {
|
||||
result = result.filter(e => e.status === filters.status);
|
||||
}
|
||||
|
||||
if (filters.startDate) {
|
||||
result = result.filter(e => e.timestamp >= filters.startDate!);
|
||||
}
|
||||
|
||||
if (filters.endDate) {
|
||||
result = result.filter(e => e.timestamp <= filters.endDate!);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 解决事件
|
||||
async resolveEvent(eventId: string, resolution: string): Promise<boolean> {
|
||||
const event = this.events.get(eventId);
|
||||
if (!event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event.status = 'resolved';
|
||||
event.metadata = {
|
||||
...event.metadata,
|
||||
resolution
|
||||
};
|
||||
this.events.set(eventId, event);
|
||||
this.eventBus.publish('governance.event.resolved', event);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 忽略事件
|
||||
async ignoreEvent(eventId: string, reason: string): Promise<boolean> {
|
||||
const event = this.events.get(eventId);
|
||||
if (!event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event.status = 'ignored';
|
||||
event.metadata = {
|
||||
...event.metadata,
|
||||
ignoreReason: reason
|
||||
};
|
||||
this.events.set(eventId, event);
|
||||
this.eventBus.publish('governance.event.ignored', event);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 设置服务配额
|
||||
async setServiceQuota(quota: Omit<ServiceQuota, 'createdAt' | 'lastUpdated'>): Promise<ServiceQuota> {
|
||||
const existingQuota = this.quotas.get(quota.serviceId);
|
||||
|
||||
const newQuota: ServiceQuota = {
|
||||
...quota,
|
||||
createdAt: existingQuota?.createdAt || new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.quotas.set(quota.serviceId, newQuota);
|
||||
this.eventBus.publish('governance.quota.set', newQuota);
|
||||
return newQuota;
|
||||
}
|
||||
|
||||
// 获取服务配额
|
||||
getServiceQuota(serviceId: string): ServiceQuota | undefined {
|
||||
return this.quotas.get(serviceId);
|
||||
}
|
||||
|
||||
// 获取所有服务配额
|
||||
getAllServiceQuotas(): ServiceQuota[] {
|
||||
return Array.from(this.quotas.values());
|
||||
}
|
||||
|
||||
// 检查服务是否符合治理规则
|
||||
async checkServiceCompliance(serviceId: string): Promise<{
|
||||
compliant: boolean;
|
||||
violations: GovernanceEvent[];
|
||||
}> {
|
||||
const service = this.serviceRegistry.getService(serviceId);
|
||||
if (!service) {
|
||||
throw new Error('Service not found');
|
||||
}
|
||||
|
||||
const violations: GovernanceEvent[] = [];
|
||||
const enabledRules = this.getAllRules({ enabled: true });
|
||||
|
||||
for (const rule of enabledRules) {
|
||||
// 这里应该有实际的规则检查逻辑
|
||||
// 暂时模拟检查
|
||||
const isViolation = Math.random() < 0.1; // 10% 概率违反规则
|
||||
|
||||
if (isViolation) {
|
||||
const violation = await this.createEvent({
|
||||
serviceId,
|
||||
ruleId: rule.id,
|
||||
severity: rule.severity,
|
||||
message: `Service ${serviceId} violates rule ${rule.name}`
|
||||
});
|
||||
violations.push(violation);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
compliant: violations.length === 0,
|
||||
violations
|
||||
};
|
||||
}
|
||||
|
||||
// 执行服务治理检查
|
||||
async runGovernanceCheck(): Promise<{
|
||||
totalServices: number;
|
||||
compliantServices: number;
|
||||
violations: GovernanceEvent[];
|
||||
}> {
|
||||
const services = this.serviceRegistry.getAllServices();
|
||||
const violations: GovernanceEvent[] = [];
|
||||
let compliantCount = 0;
|
||||
|
||||
for (const service of services) {
|
||||
const result = await this.checkServiceCompliance(service.id);
|
||||
if (result.compliant) {
|
||||
compliantCount++;
|
||||
} else {
|
||||
violations.push(...result.violations);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
totalServices: services.length,
|
||||
compliantServices: compliantCount,
|
||||
violations
|
||||
};
|
||||
}
|
||||
|
||||
// 获取治理统计信息
|
||||
getGovernanceStats(): {
|
||||
totalRules: number;
|
||||
enabledRules: number;
|
||||
totalEvents: number;
|
||||
openEvents: number;
|
||||
resolvedEvents: number;
|
||||
ignoredEvents: number;
|
||||
compliantServices: number;
|
||||
totalServices: number;
|
||||
} {
|
||||
const totalServices = this.serviceRegistry.getAllServices().length;
|
||||
const compliantServices = 0; // 这里应该计算实际的合规服务数量
|
||||
|
||||
return {
|
||||
totalRules: this.rules.size,
|
||||
enabledRules: Array.from(this.rules.values()).filter(r => r.enabled).length,
|
||||
totalEvents: this.events.size,
|
||||
openEvents: Array.from(this.events.values()).filter(e => e.status === 'open').length,
|
||||
resolvedEvents: Array.from(this.events.values()).filter(e => e.status === 'resolved').length,
|
||||
ignoredEvents: Array.from(this.events.values()).filter(e => e.status === 'ignored').length,
|
||||
compliantServices,
|
||||
totalServices
|
||||
};
|
||||
}
|
||||
}
|
||||
323
server/src/core/governance/StrategyMarketplace.ts
Normal file
323
server/src/core/governance/StrategyMarketplace.ts
Normal file
@@ -0,0 +1,323 @@
|
||||
import { DomainEventBus } from '../runtime/DomainEventBus';
|
||||
|
||||
// 策略信息
|
||||
export interface Strategy {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
type: 'pricing' | 'product_selection' | 'marketing' | 'logistics' | 'risk';
|
||||
version: string;
|
||||
developerId: string;
|
||||
price: number;
|
||||
rating: number;
|
||||
usageCount: number;
|
||||
status: 'draft' | 'published' | 'archived';
|
||||
tags: string[];
|
||||
createdAt: Date;
|
||||
lastUpdated: Date;
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
// 策略订阅
|
||||
export interface StrategySubscription {
|
||||
id: string;
|
||||
strategyId: string;
|
||||
merchantId: string;
|
||||
status: 'active' | 'expired' | 'cancelled';
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
price: number;
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
// 策略评价
|
||||
export interface StrategyReview {
|
||||
id: string;
|
||||
strategyId: string;
|
||||
merchantId: string;
|
||||
rating: number; // 1-5
|
||||
comment: string;
|
||||
createdAt: Date;
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
// 策略市场
|
||||
export class StrategyMarketplace {
|
||||
private static instance: StrategyMarketplace;
|
||||
private strategies: Map<string, Strategy> = new Map();
|
||||
private subscriptions: Map<string, StrategySubscription> = new Map();
|
||||
private reviews: Map<string, StrategyReview> = new Map();
|
||||
private eventBus: DomainEventBus;
|
||||
|
||||
private constructor() {
|
||||
this.eventBus = DomainEventBus.getInstance();
|
||||
}
|
||||
|
||||
static getInstance(): StrategyMarketplace {
|
||||
if (!StrategyMarketplace.instance) {
|
||||
StrategyMarketplace.instance = new StrategyMarketplace();
|
||||
}
|
||||
return StrategyMarketplace.instance;
|
||||
}
|
||||
|
||||
// 发布策略
|
||||
async publishStrategy(strategy: Omit<Strategy, 'id' | 'rating' | 'usageCount' | 'status' | 'createdAt' | 'lastUpdated'>): Promise<Strategy> {
|
||||
const id = `strategy_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const newStrategy: Strategy = {
|
||||
...strategy,
|
||||
id,
|
||||
rating: 0,
|
||||
usageCount: 0,
|
||||
status: 'published',
|
||||
createdAt: new Date(),
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.strategies.set(id, newStrategy);
|
||||
this.eventBus.publish('strategy.published', newStrategy);
|
||||
return newStrategy;
|
||||
}
|
||||
|
||||
// 获取策略信息
|
||||
getStrategy(strategyId: string): Strategy | undefined {
|
||||
return this.strategies.get(strategyId);
|
||||
}
|
||||
|
||||
// 获取所有策略
|
||||
getAllStrategies(filters?: {
|
||||
type?: string;
|
||||
tags?: string[];
|
||||
minRating?: number;
|
||||
maxPrice?: number;
|
||||
}): Strategy[] {
|
||||
let result = Array.from(this.strategies.values());
|
||||
|
||||
if (filters) {
|
||||
if (filters.type) {
|
||||
result = result.filter(s => s.type === filters.type);
|
||||
}
|
||||
|
||||
if (filters.tags && filters.tags.length > 0) {
|
||||
result = result.filter(s => filters.tags!.some(tag => s.tags.includes(tag)));
|
||||
}
|
||||
|
||||
if (filters.minRating !== undefined) {
|
||||
result = result.filter(s => s.rating >= filters.minRating!);
|
||||
}
|
||||
|
||||
if (filters.maxPrice !== undefined) {
|
||||
result = result.filter(s => s.price <= filters.maxPrice!);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取开发者的策略
|
||||
getDeveloperStrategies(developerId: string): Strategy[] {
|
||||
return Array.from(this.strategies.values()).filter(s => s.developerId === developerId);
|
||||
}
|
||||
|
||||
// 更新策略
|
||||
async updateStrategy(strategyId: string, updates: Partial<Strategy>): Promise<Strategy | null> {
|
||||
const strategy = this.strategies.get(strategyId);
|
||||
if (!strategy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedStrategy = {
|
||||
...strategy,
|
||||
...updates,
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
|
||||
this.strategies.set(strategyId, updatedStrategy);
|
||||
this.eventBus.publish('strategy.updated', updatedStrategy);
|
||||
return updatedStrategy;
|
||||
}
|
||||
|
||||
// 归档策略
|
||||
async archiveStrategy(strategyId: string): Promise<boolean> {
|
||||
const strategy = this.strategies.get(strategyId);
|
||||
if (!strategy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strategy.status = 'archived';
|
||||
strategy.lastUpdated = new Date();
|
||||
this.strategies.set(strategyId, strategy);
|
||||
this.eventBus.publish('strategy.archived', strategy);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 订阅策略
|
||||
async subscribeToStrategy(strategyId: string, merchantId: string, durationDays: number = 30): Promise<StrategySubscription> {
|
||||
const strategy = this.strategies.get(strategyId);
|
||||
if (!strategy || strategy.status !== 'published') {
|
||||
throw new Error('Strategy not available');
|
||||
}
|
||||
|
||||
const id = `sub_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
const startDate = new Date();
|
||||
const endDate = new Date();
|
||||
endDate.setDate(endDate.getDate() + durationDays);
|
||||
|
||||
const subscription: StrategySubscription = {
|
||||
id,
|
||||
strategyId,
|
||||
merchantId,
|
||||
status: 'active',
|
||||
startDate,
|
||||
endDate,
|
||||
price: strategy.price * (durationDays / 30)
|
||||
};
|
||||
|
||||
this.subscriptions.set(id, subscription);
|
||||
|
||||
// 更新策略使用次数
|
||||
strategy.usageCount++;
|
||||
this.strategies.set(strategyId, strategy);
|
||||
|
||||
this.eventBus.publish('strategy.subscribed', subscription);
|
||||
return subscription;
|
||||
}
|
||||
|
||||
// 获取订阅信息
|
||||
getSubscription(subscriptionId: string): StrategySubscription | undefined {
|
||||
return this.subscriptions.get(subscriptionId);
|
||||
}
|
||||
|
||||
// 获取商户的订阅
|
||||
getMerchantSubscriptions(merchantId: string): StrategySubscription[] {
|
||||
return Array.from(this.subscriptions.values()).filter(s => s.merchantId === merchantId);
|
||||
}
|
||||
|
||||
// 获取策略的订阅
|
||||
getStrategySubscriptions(strategyId: string): StrategySubscription[] {
|
||||
return Array.from(this.subscriptions.values()).filter(s => s.strategyId === strategyId);
|
||||
}
|
||||
|
||||
// 取消订阅
|
||||
async cancelSubscription(subscriptionId: string): Promise<boolean> {
|
||||
const subscription = this.subscriptions.get(subscriptionId);
|
||||
if (!subscription) {
|
||||
return false;
|
||||
}
|
||||
|
||||
subscription.status = 'cancelled';
|
||||
this.subscriptions.set(subscriptionId, subscription);
|
||||
this.eventBus.publish('subscription.cancelled', subscription);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 评价策略
|
||||
async reviewStrategy(strategyId: string, merchantId: string, rating: number, comment: string): Promise<StrategyReview> {
|
||||
const strategy = this.strategies.get(strategyId);
|
||||
if (!strategy) {
|
||||
throw new Error('Strategy not found');
|
||||
}
|
||||
|
||||
// 检查商户是否订阅过该策略
|
||||
const hasSubscription = Array.from(this.subscriptions.values()).some(
|
||||
s => s.strategyId === strategyId && s.merchantId === merchantId
|
||||
);
|
||||
|
||||
if (!hasSubscription) {
|
||||
throw new Error('Merchant has not subscribed to this strategy');
|
||||
}
|
||||
|
||||
const id = `review_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const review: StrategyReview = {
|
||||
id,
|
||||
strategyId,
|
||||
merchantId,
|
||||
rating,
|
||||
comment,
|
||||
createdAt: new Date()
|
||||
};
|
||||
|
||||
this.reviews.set(id, review);
|
||||
|
||||
// 更新策略评分
|
||||
this.updateStrategyRating(strategyId);
|
||||
|
||||
this.eventBus.publish('strategy.reviewed', review);
|
||||
return review;
|
||||
}
|
||||
|
||||
// 获取策略的评价
|
||||
getStrategyReviews(strategyId: string): StrategyReview[] {
|
||||
return Array.from(this.reviews.values()).filter(r => r.strategyId === strategyId);
|
||||
}
|
||||
|
||||
// 更新策略评分
|
||||
private updateStrategyRating(strategyId: string): void {
|
||||
const reviews = this.getStrategyReviews(strategyId);
|
||||
if (reviews.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const totalRating = reviews.reduce((sum, review) => sum + review.rating, 0);
|
||||
const averageRating = totalRating / reviews.length;
|
||||
|
||||
const strategy = this.strategies.get(strategyId);
|
||||
if (strategy) {
|
||||
strategy.rating = averageRating;
|
||||
strategy.lastUpdated = new Date();
|
||||
this.strategies.set(strategyId, strategy);
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索策略
|
||||
searchStrategies(query: string, filters?: {
|
||||
type?: string;
|
||||
minRating?: number;
|
||||
maxPrice?: number;
|
||||
}): Strategy[] {
|
||||
let result = Array.from(this.strategies.values());
|
||||
|
||||
// 关键词搜索
|
||||
if (query) {
|
||||
const lowerQuery = query.toLowerCase();
|
||||
result = result.filter(s =>
|
||||
s.name.toLowerCase().includes(lowerQuery) ||
|
||||
s.description.toLowerCase().includes(lowerQuery) ||
|
||||
s.tags.some(tag => tag.toLowerCase().includes(lowerQuery))
|
||||
);
|
||||
}
|
||||
|
||||
// 应用过滤器
|
||||
if (filters) {
|
||||
if (filters.type) {
|
||||
result = result.filter(s => s.type === filters.type);
|
||||
}
|
||||
|
||||
if (filters.minRating !== undefined) {
|
||||
result = result.filter(s => s.rating >= filters.minRating!);
|
||||
}
|
||||
|
||||
if (filters.maxPrice !== undefined) {
|
||||
result = result.filter(s => s.price <= filters.maxPrice!);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取热门策略
|
||||
getPopularStrategies(limit: number = 10): Strategy[] {
|
||||
return Array.from(this.strategies.values())
|
||||
.filter(s => s.status === 'published')
|
||||
.sort((a, b) => b.usageCount - a.usageCount)
|
||||
.slice(0, limit);
|
||||
}
|
||||
|
||||
// 获取推荐策略
|
||||
getRecommendedStrategies(merchantId: string, limit: number = 5): Strategy[] {
|
||||
// 这里应该有推荐算法
|
||||
// 暂时返回热门策略
|
||||
return this.getPopularStrategies(limit);
|
||||
}
|
||||
}
|
||||
266
server/src/core/orchestrator/ServiceMonitor.ts
Normal file
266
server/src/core/orchestrator/ServiceMonitor.ts
Normal file
@@ -0,0 +1,266 @@
|
||||
import { DomainEventBus } from '../runtime/DomainEventBus';
|
||||
import { ServiceOrchestrator, ServiceStatus } from './ServiceOrchestrator';
|
||||
import { ServiceRegistry } from './ServiceRegistry';
|
||||
|
||||
// 服务监控指标
|
||||
export interface ServiceMetrics {
|
||||
serviceId: string;
|
||||
status: ServiceStatus;
|
||||
responseTime: number; // 毫秒
|
||||
errorRate: number; // 错误率
|
||||
throughput: number; // 每秒请求数
|
||||
lastHealthCheck: Date;
|
||||
uptime: number; // 秒
|
||||
memoryUsage?: number; // 内存使用量(MB)
|
||||
cpuUsage?: number; // CPU使用率(%)
|
||||
}
|
||||
|
||||
// 服务监控配置
|
||||
export interface MonitorConfig {
|
||||
healthCheckInterval: number; // 健康检查间隔(毫秒)
|
||||
metricsCollectionInterval: number; // 指标收集间隔(毫秒)
|
||||
alertThresholds: {
|
||||
errorRate: number;
|
||||
responseTime: number;
|
||||
uptime: number;
|
||||
};
|
||||
}
|
||||
|
||||
// 服务监控器
|
||||
export class ServiceMonitor {
|
||||
private static instance: ServiceMonitor;
|
||||
private serviceOrchestrator: ServiceOrchestrator;
|
||||
private serviceRegistry: ServiceRegistry;
|
||||
private eventBus: DomainEventBus;
|
||||
private metrics: Map<string, ServiceMetrics> = new Map();
|
||||
private config: MonitorConfig;
|
||||
private healthCheckTimers: Map<string, NodeJS.Timeout> = new Map();
|
||||
private metricsCollectionTimer: NodeJS.Timeout | null = null;
|
||||
|
||||
private constructor() {
|
||||
this.serviceOrchestrator = ServiceOrchestrator.getInstance();
|
||||
this.serviceRegistry = ServiceRegistry.getInstance();
|
||||
this.eventBus = DomainEventBus.getInstance();
|
||||
|
||||
this.config = {
|
||||
healthCheckInterval: 30000, // 30秒
|
||||
metricsCollectionInterval: 60000, // 60秒
|
||||
alertThresholds: {
|
||||
errorRate: 0.1, // 10%
|
||||
responseTime: 1000, // 1秒
|
||||
uptime: 86400, // 24小时
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static getInstance(): ServiceMonitor {
|
||||
if (!ServiceMonitor.instance) {
|
||||
ServiceMonitor.instance = new ServiceMonitor();
|
||||
}
|
||||
return ServiceMonitor.instance;
|
||||
}
|
||||
|
||||
// 启动监控
|
||||
startMonitoring(): void {
|
||||
// 启动指标收集
|
||||
this.startMetricsCollection();
|
||||
|
||||
// 为每个服务启动健康检查
|
||||
for (const service of this.serviceRegistry.getAllServices()) {
|
||||
this.startHealthCheck(service.id);
|
||||
}
|
||||
|
||||
// 监听服务注册事件
|
||||
this.eventBus.subscribe('service.registered', (data: { serviceId: string }) => {
|
||||
this.startHealthCheck(data.serviceId);
|
||||
});
|
||||
|
||||
// 监听服务状态变更事件
|
||||
this.eventBus.subscribe('service.started', (data: { serviceId: string }) => {
|
||||
this.updateMetrics(data.serviceId);
|
||||
});
|
||||
|
||||
this.eventBus.subscribe('service.stopped', (data: { serviceId: string }) => {
|
||||
this.updateMetrics(data.serviceId);
|
||||
});
|
||||
|
||||
this.eventBus.subscribe('service.error', (data: { serviceId: string, error: string }) => {
|
||||
this.updateMetrics(data.serviceId);
|
||||
this.sendAlert(data.serviceId, `Service error: ${data.error}`);
|
||||
});
|
||||
|
||||
this.eventBus.subscribe('service.recovered', (data: { serviceId: string }) => {
|
||||
this.updateMetrics(data.serviceId);
|
||||
this.sendAlert(data.serviceId, 'Service recovered', 'info');
|
||||
});
|
||||
}
|
||||
|
||||
// 停止监控
|
||||
stopMonitoring(): void {
|
||||
// 停止健康检查
|
||||
for (const [serviceId, timer] of this.healthCheckTimers) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
this.healthCheckTimers.clear();
|
||||
|
||||
// 停止指标收集
|
||||
if (this.metricsCollectionTimer) {
|
||||
clearInterval(this.metricsCollectionTimer);
|
||||
this.metricsCollectionTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 启动健康检查
|
||||
private startHealthCheck(serviceId: string): void {
|
||||
if (this.healthCheckTimers.has(serviceId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timer = setInterval(async () => {
|
||||
try {
|
||||
const healthy = await this.serviceOrchestrator.healthCheck(serviceId);
|
||||
if (!healthy) {
|
||||
this.sendAlert(serviceId, 'Service health check failed');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error checking health for service ${serviceId}:`, error);
|
||||
}
|
||||
}, this.config.healthCheckInterval);
|
||||
|
||||
this.healthCheckTimers.set(serviceId, timer);
|
||||
}
|
||||
|
||||
// 停止健康检查
|
||||
private stopHealthCheck(serviceId: string): void {
|
||||
const timer = this.healthCheckTimers.get(serviceId);
|
||||
if (timer) {
|
||||
clearInterval(timer);
|
||||
this.healthCheckTimers.delete(serviceId);
|
||||
}
|
||||
}
|
||||
|
||||
// 启动指标收集
|
||||
private startMetricsCollection(): void {
|
||||
if (this.metricsCollectionTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.metricsCollectionTimer = setInterval(() => {
|
||||
this.collectMetrics();
|
||||
}, this.config.metricsCollectionInterval);
|
||||
}
|
||||
|
||||
// 收集指标
|
||||
private collectMetrics(): void {
|
||||
for (const service of this.serviceRegistry.getAllServices()) {
|
||||
this.updateMetrics(service.id);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新指标
|
||||
private updateMetrics(serviceId: string): void {
|
||||
const status = this.serviceOrchestrator.getServiceStatus(serviceId);
|
||||
if (!status) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentMetrics = this.metrics.get(serviceId) || {
|
||||
serviceId,
|
||||
status: 'stopped' as ServiceStatus,
|
||||
responseTime: 0,
|
||||
errorRate: 0,
|
||||
throughput: 0,
|
||||
lastHealthCheck: new Date(),
|
||||
uptime: 0
|
||||
};
|
||||
|
||||
const newMetrics: ServiceMetrics = {
|
||||
...currentMetrics,
|
||||
status,
|
||||
lastHealthCheck: new Date(),
|
||||
// 这里应该有实际的指标收集逻辑
|
||||
// 暂时使用模拟数据
|
||||
responseTime: Math.random() * 500,
|
||||
errorRate: Math.random() * 0.05,
|
||||
throughput: Math.random() * 100,
|
||||
uptime: currentMetrics.uptime + (this.config.metricsCollectionInterval / 1000)
|
||||
};
|
||||
|
||||
this.metrics.set(serviceId, newMetrics);
|
||||
|
||||
// 检查是否需要告警
|
||||
this.checkAlertThresholds(newMetrics);
|
||||
|
||||
// 发布指标更新事件
|
||||
this.eventBus.publish('service.metrics.updated', newMetrics);
|
||||
}
|
||||
|
||||
// 检查告警阈值
|
||||
private checkAlertThresholds(metrics: ServiceMetrics): void {
|
||||
if (metrics.errorRate > this.config.alertThresholds.errorRate) {
|
||||
this.sendAlert(metrics.serviceId, `High error rate: ${(metrics.errorRate * 100).toFixed(2)}%`);
|
||||
}
|
||||
|
||||
if (metrics.responseTime > this.config.alertThresholds.responseTime) {
|
||||
this.sendAlert(metrics.serviceId, `High response time: ${metrics.responseTime.toFixed(2)}ms`);
|
||||
}
|
||||
|
||||
if (metrics.uptime < this.config.alertThresholds.uptime) {
|
||||
this.sendAlert(metrics.serviceId, `Low uptime: ${(metrics.uptime / 3600).toFixed(2)} hours`);
|
||||
}
|
||||
}
|
||||
|
||||
// 发送告警
|
||||
private sendAlert(serviceId: string, message: string, level: 'error' | 'warning' | 'info' = 'error'): void {
|
||||
console.log(`[${level.toUpperCase()}] Service ${serviceId}: ${message}`);
|
||||
this.eventBus.publish('service.alert', { serviceId, message, level, timestamp: new Date() });
|
||||
}
|
||||
|
||||
// 获取服务指标
|
||||
getServiceMetrics(serviceId: string): ServiceMetrics | undefined {
|
||||
return this.metrics.get(serviceId);
|
||||
}
|
||||
|
||||
// 获取所有服务指标
|
||||
getAllServiceMetrics(): ServiceMetrics[] {
|
||||
return Array.from(this.metrics.values());
|
||||
}
|
||||
|
||||
// 获取服务健康状态
|
||||
getServiceHealth(serviceId: string): 'healthy' | 'unhealthy' | 'unknown' {
|
||||
const metrics = this.metrics.get(serviceId);
|
||||
if (!metrics) {
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
if (metrics.status === 'running' && metrics.errorRate < 0.05 && metrics.responseTime < 500) {
|
||||
return 'healthy';
|
||||
}
|
||||
|
||||
return 'unhealthy';
|
||||
}
|
||||
|
||||
// 获取所有服务健康状态
|
||||
getAllServiceHealth(): Map<string, 'healthy' | 'unhealthy' | 'unknown'> {
|
||||
const healthStatus = new Map<string, 'healthy' | 'unhealthy' | 'unknown'>();
|
||||
|
||||
for (const service of this.serviceRegistry.getAllServices()) {
|
||||
healthStatus.set(service.id, this.getServiceHealth(service.id));
|
||||
}
|
||||
|
||||
return healthStatus;
|
||||
}
|
||||
|
||||
// 设置监控配置
|
||||
setConfig(config: Partial<MonitorConfig>): void {
|
||||
this.config = {
|
||||
...this.config,
|
||||
...config
|
||||
};
|
||||
}
|
||||
|
||||
// 获取监控配置
|
||||
getConfig(): MonitorConfig {
|
||||
return { ...this.config };
|
||||
}
|
||||
}
|
||||
261
server/src/core/orchestrator/ServiceOrchestrator.ts
Normal file
261
server/src/core/orchestrator/ServiceOrchestrator.ts
Normal file
@@ -0,0 +1,261 @@
|
||||
import { DomainEventBus } from '../runtime/DomainEventBus';
|
||||
import { ServiceRegistry } from './ServiceRegistry';
|
||||
import { ServiceMonitor } from './ServiceMonitor';
|
||||
|
||||
// 服务类型定义
|
||||
export interface ServiceDefinition {
|
||||
id: string;
|
||||
name: string;
|
||||
version: string;
|
||||
dependencies: string[];
|
||||
healthCheck: () => Promise<boolean>;
|
||||
start: () => Promise<void>;
|
||||
stop: () => Promise<void>;
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
// 服务状态
|
||||
export type ServiceStatus = 'stopped' | 'starting' | 'running' | 'stopping' | 'error';
|
||||
|
||||
// 服务实例
|
||||
export interface ServiceInstance {
|
||||
definition: ServiceDefinition;
|
||||
status: ServiceStatus;
|
||||
lastHealthCheck: Date;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
// 服务编排器
|
||||
export class ServiceOrchestrator {
|
||||
private static instance: ServiceOrchestrator;
|
||||
private serviceRegistry: ServiceRegistry;
|
||||
private serviceMonitor: ServiceMonitor;
|
||||
private serviceInstances: Map<string, ServiceInstance> = new Map();
|
||||
private eventBus: DomainEventBus;
|
||||
|
||||
private constructor() {
|
||||
this.serviceRegistry = ServiceRegistry.getInstance();
|
||||
this.serviceMonitor = ServiceMonitor.getInstance();
|
||||
this.eventBus = DomainEventBus.getInstance();
|
||||
}
|
||||
|
||||
static getInstance(): ServiceOrchestrator {
|
||||
if (!ServiceOrchestrator.instance) {
|
||||
ServiceOrchestrator.instance = new ServiceOrchestrator();
|
||||
}
|
||||
return ServiceOrchestrator.instance;
|
||||
}
|
||||
|
||||
// 注册服务
|
||||
async registerService(service: ServiceDefinition): Promise<void> {
|
||||
// 验证服务依赖
|
||||
for (const dependency of service.dependencies) {
|
||||
if (!this.serviceRegistry.getService(dependency)) {
|
||||
throw new Error(`Dependency ${dependency} not found`);
|
||||
}
|
||||
}
|
||||
|
||||
// 注册到服务注册表
|
||||
await this.serviceRegistry.registerService(service);
|
||||
|
||||
// 创建服务实例
|
||||
const instance: ServiceInstance = {
|
||||
definition: service,
|
||||
status: 'stopped',
|
||||
lastHealthCheck: new Date()
|
||||
};
|
||||
|
||||
this.serviceInstances.set(service.id, instance);
|
||||
this.eventBus.publish('service.registered', { serviceId: service.id });
|
||||
}
|
||||
|
||||
// 启动服务
|
||||
async startService(serviceId: string): Promise<void> {
|
||||
const instance = this.serviceInstances.get(serviceId);
|
||||
if (!instance) {
|
||||
throw new Error(`Service ${serviceId} not found`);
|
||||
}
|
||||
|
||||
if (instance.status === 'running') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 启动依赖服务
|
||||
for (const dependencyId of instance.definition.dependencies) {
|
||||
await this.startService(dependencyId);
|
||||
}
|
||||
|
||||
instance.status = 'starting';
|
||||
this.eventBus.publish('service.starting', { serviceId });
|
||||
|
||||
try {
|
||||
await instance.definition.start();
|
||||
instance.status = 'running';
|
||||
instance.lastHealthCheck = new Date();
|
||||
this.eventBus.publish('service.started', { serviceId });
|
||||
} catch (error) {
|
||||
instance.status = 'error';
|
||||
instance.error = error instanceof Error ? error.message : String(error);
|
||||
this.eventBus.publish('service.error', { serviceId, error: instance.error });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 停止服务
|
||||
async stopService(serviceId: string): Promise<void> {
|
||||
const instance = this.serviceInstances.get(serviceId);
|
||||
if (!instance) {
|
||||
throw new Error(`Service ${serviceId} not found`);
|
||||
}
|
||||
|
||||
if (instance.status === 'stopped') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否有其他服务依赖此服务
|
||||
const dependentServices = Array.from(this.serviceInstances.values())
|
||||
.filter(s => s.definition.dependencies.includes(serviceId));
|
||||
|
||||
if (dependentServices.length > 0) {
|
||||
throw new Error(`Service ${serviceId} is being used by other services: ${dependentServices.map(s => s.definition.id).join(', ')}`);
|
||||
}
|
||||
|
||||
instance.status = 'stopping';
|
||||
this.eventBus.publish('service.stopping', { serviceId });
|
||||
|
||||
try {
|
||||
await instance.definition.stop();
|
||||
instance.status = 'stopped';
|
||||
this.eventBus.publish('service.stopped', { serviceId });
|
||||
} catch (error) {
|
||||
instance.status = 'error';
|
||||
instance.error = error instanceof Error ? error.message : String(error);
|
||||
this.eventBus.publish('service.error', { serviceId, error: instance.error });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 启动所有服务
|
||||
async startAllServices(): Promise<void> {
|
||||
const services = Array.from(this.serviceInstances.values());
|
||||
|
||||
// 按依赖顺序排序
|
||||
const sortedServices = this.topologicalSort(services);
|
||||
|
||||
for (const service of sortedServices) {
|
||||
await this.startService(service.definition.id);
|
||||
}
|
||||
}
|
||||
|
||||
// 停止所有服务
|
||||
async stopAllServices(): Promise<void> {
|
||||
const services = Array.from(this.serviceInstances.values());
|
||||
|
||||
// 按依赖顺序的逆序排序
|
||||
const sortedServices = this.topologicalSort(services).reverse();
|
||||
|
||||
for (const service of sortedServices) {
|
||||
try {
|
||||
await this.stopService(service.definition.id);
|
||||
} catch (error) {
|
||||
console.error(`Error stopping service ${service.definition.id}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 拓扑排序服务依赖
|
||||
private topologicalSort(services: ServiceInstance[]): ServiceInstance[] {
|
||||
const visited = new Set<string>();
|
||||
const temp = new Set<string>();
|
||||
const result: ServiceInstance[] = [];
|
||||
|
||||
const visit = (serviceId: string) => {
|
||||
if (temp.has(serviceId)) {
|
||||
throw new Error('Circular dependency detected');
|
||||
}
|
||||
|
||||
if (visited.has(serviceId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
temp.add(serviceId);
|
||||
|
||||
const service = services.find(s => s.definition.id === serviceId);
|
||||
if (service) {
|
||||
for (const dependencyId of service.definition.dependencies) {
|
||||
visit(dependencyId);
|
||||
}
|
||||
}
|
||||
|
||||
temp.delete(serviceId);
|
||||
visited.add(serviceId);
|
||||
|
||||
const foundService = services.find(s => s.definition.id === serviceId);
|
||||
if (foundService) {
|
||||
result.push(foundService);
|
||||
}
|
||||
};
|
||||
|
||||
for (const service of services) {
|
||||
if (!visited.has(service.definition.id)) {
|
||||
visit(service.definition.id);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取服务状态
|
||||
getServiceStatus(serviceId: string): ServiceStatus | undefined {
|
||||
const instance = this.serviceInstances.get(serviceId);
|
||||
return instance?.status;
|
||||
}
|
||||
|
||||
// 获取所有服务状态
|
||||
getAllServiceStatuses(): Map<string, ServiceStatus> {
|
||||
const statuses = new Map<string, ServiceStatus>();
|
||||
for (const [id, instance] of this.serviceInstances) {
|
||||
statuses.set(id, instance.status);
|
||||
}
|
||||
return statuses;
|
||||
}
|
||||
|
||||
// 健康检查
|
||||
async healthCheck(serviceId: string): Promise<boolean> {
|
||||
const instance = this.serviceInstances.get(serviceId);
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const healthy = await instance.definition.healthCheck();
|
||||
instance.lastHealthCheck = new Date();
|
||||
|
||||
if (instance.status === 'error' && healthy) {
|
||||
instance.status = 'running';
|
||||
instance.error = undefined;
|
||||
this.eventBus.publish('service.recovered', { serviceId });
|
||||
}
|
||||
|
||||
return healthy;
|
||||
} catch (error) {
|
||||
instance.status = 'error';
|
||||
instance.error = error instanceof Error ? error.message : String(error);
|
||||
instance.lastHealthCheck = new Date();
|
||||
this.eventBus.publish('service.error', { serviceId, error: instance.error });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 执行所有服务的健康检查
|
||||
async healthCheckAll(): Promise<Map<string, boolean>> {
|
||||
const results = new Map<string, boolean>();
|
||||
|
||||
for (const serviceId of this.serviceInstances.keys()) {
|
||||
const healthy = await this.healthCheck(serviceId);
|
||||
results.set(serviceId, healthy);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
133
server/src/core/orchestrator/ServiceRegistry.ts
Normal file
133
server/src/core/orchestrator/ServiceRegistry.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import { ServiceDefinition } from './ServiceOrchestrator';
|
||||
|
||||
// 服务注册表
|
||||
export class ServiceRegistry {
|
||||
private static instance: ServiceRegistry;
|
||||
private services: Map<string, ServiceDefinition> = new Map();
|
||||
private serviceIndex: Map<string, string[]> = new Map(); // 按名称索引服务
|
||||
|
||||
private constructor() {}
|
||||
|
||||
static getInstance(): ServiceRegistry {
|
||||
if (!ServiceRegistry.instance) {
|
||||
ServiceRegistry.instance = new ServiceRegistry();
|
||||
}
|
||||
return ServiceRegistry.instance;
|
||||
}
|
||||
|
||||
// 注册服务
|
||||
async registerService(service: ServiceDefinition): Promise<void> {
|
||||
if (this.services.has(service.id)) {
|
||||
throw new Error(`Service with id ${service.id} already exists`);
|
||||
}
|
||||
|
||||
this.services.set(service.id, service);
|
||||
|
||||
// 按名称索引
|
||||
if (!this.serviceIndex.has(service.name)) {
|
||||
this.serviceIndex.set(service.name, []);
|
||||
}
|
||||
this.serviceIndex.get(service.name)?.push(service.id);
|
||||
}
|
||||
|
||||
// 注销服务
|
||||
async unregisterService(serviceId: string): Promise<void> {
|
||||
const service = this.services.get(serviceId);
|
||||
if (!service) {
|
||||
throw new Error(`Service ${serviceId} not found`);
|
||||
}
|
||||
|
||||
this.services.delete(serviceId);
|
||||
|
||||
// 更新名称索引
|
||||
const serviceIds = this.serviceIndex.get(service.name);
|
||||
if (serviceIds) {
|
||||
const index = serviceIds.indexOf(serviceId);
|
||||
if (index !== -1) {
|
||||
serviceIds.splice(index, 1);
|
||||
if (serviceIds.length === 0) {
|
||||
this.serviceIndex.delete(service.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取服务
|
||||
getService(serviceId: string): ServiceDefinition | undefined {
|
||||
return this.services.get(serviceId);
|
||||
}
|
||||
|
||||
// 根据名称获取服务
|
||||
getServicesByName(name: string): ServiceDefinition[] {
|
||||
const serviceIds = this.serviceIndex.get(name) || [];
|
||||
return serviceIds.map(id => this.services.get(id)).filter((s): s is ServiceDefinition => s !== undefined);
|
||||
}
|
||||
|
||||
// 获取所有服务
|
||||
getAllServices(): ServiceDefinition[] {
|
||||
return Array.from(this.services.values());
|
||||
}
|
||||
|
||||
// 检查服务是否存在
|
||||
hasService(serviceId: string): boolean {
|
||||
return this.services.has(serviceId);
|
||||
}
|
||||
|
||||
// 获取服务依赖图
|
||||
getDependencyGraph(): Map<string, string[]> {
|
||||
const graph = new Map<string, string[]>();
|
||||
|
||||
for (const [id, service] of this.services) {
|
||||
graph.set(id, service.dependencies);
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
// 验证服务依赖
|
||||
validateDependencies(): { valid: boolean; errors: string[] } {
|
||||
const errors: string[] = [];
|
||||
|
||||
for (const [id, service] of this.services) {
|
||||
for (const dependencyId of service.dependencies) {
|
||||
if (!this.services.has(dependencyId)) {
|
||||
errors.push(`Service ${id} depends on non-existent service ${dependencyId}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
valid: errors.length === 0,
|
||||
errors
|
||||
};
|
||||
}
|
||||
|
||||
// 导出服务注册表
|
||||
exportRegistry(): Record<string, ServiceDefinition> {
|
||||
const registry: Record<string, ServiceDefinition> = {};
|
||||
|
||||
for (const [id, service] of this.services) {
|
||||
registry[id] = service;
|
||||
}
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
// 导入服务注册表
|
||||
async importRegistry(registry: Record<string, ServiceDefinition>): Promise<void> {
|
||||
for (const [id, service] of Object.entries(registry)) {
|
||||
await this.registerService(service);
|
||||
}
|
||||
}
|
||||
|
||||
// 清空服务注册表
|
||||
clear(): void {
|
||||
this.services.clear();
|
||||
this.serviceIndex.clear();
|
||||
}
|
||||
|
||||
// 获取服务数量
|
||||
size(): number {
|
||||
return this.services.size;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user