欢迎各位观众大大浏览阅读我的博客,有空麻烦加一下博客主页关注,谢谢
MES/ERP 多段业务组轴式多线程执行框架解决方案
你需要的是针对 MES/ERP 场景中业务逻辑相关但功能段落独立、复杂琐碎 的特点,构建一套组轴式(支轴化)多线程执行框架------ 将零散的业务段落按业务逻辑关联性进行 "组轴" 归类,再基于多结构模型实现各轴的并行执行与组装拼接,最终形成包含可视化界面、后台调度引擎、标准化 API 的完整信息服务中间件方案,核心目标是既保证业务逻辑的关联性,又实现独立段落的并发执行,提升整体处理效率。
本次方案的核心创新在于 "组轴化" 设计:将业务逻辑拆解为主执行轴 (核心流程)+分支执行轴(独立段落),主轴控制整体逻辑,分支轴并行执行,最终将分支结果组装拼接,完美适配 "相关但独立" 的业务特征。
一、核心设计理念
1. 业务特征与技术映射
| MES/ERP 业务特征 | 组轴式框架解决方案 |
|---|---|
| 业务逻辑整体相关(如工单处理全流程) | 主执行轴(MasterAxis):管控整体业务逻辑、状态流转、结果汇总 |
| 功能段落独立不相关(如查询 / 更新 / 推送 / 计算) | 分支执行轴(BranchAxis):每个独立段落封装为分支轴,多线程并行执行 |
| 段落数量多、逻辑琐碎、易出错 | 轴节点(AxisNode):最小业务单元原子化封装,参数化配置 |
| 多结构(产线 / 工单 / 工序)并发需求 | 多结构轴池(MultiStructureAxisPool):按结构类型隔离执行资源 |
| 执行结果需要组装拼接 | 结果组装器(ResultAssembler):统一整合各分支轴执行结果 |
2. 整体架构

3. 核心技术选型
- 多线程框架:.NET TPL + 自定义线程池 + 信号量控制
- 设计模式:组合模式(轴 - 节点)+ 策略模式(执行策略)+ 工厂模式(轴创建)
- 并发控制:分级 SemaphoreSlim + 读写锁 + Concurrent 集合
- 通信层 :ASP.NET Core Web API + SignalR(实时状态推送)
- 界面层:WinForm + DevExpress(增强控件) + 实时进度面板
- 配置管理:JSON 配置 + 数据库存储(轴配置持久化)
二、核心组件实现
1. 组轴式核心模型定义
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
#region 核心枚举定义
/// <summary>
/// 执行轴类型
/// </summary>
public enum ExecutionAxisType
{
Master, // 主执行轴(管控整体流程)
Branch // 分支执行轴(独立业务段落)
}
/// <summary>
/// 轴节点类型
/// </summary>
public enum AxisNodeType
{
DataQuery, // 数据查询
DataUpdate, // 数据更新
ApiCall, // API调用
Calculation, // 计算处理
FileOperation, // 文件操作
DeviceCommand // 设备指令
}
/// <summary>
/// 轴执行状态
/// </summary>
public enum AxisExecutionStatus
{
Created, // 已创建
Running, // 执行中
Completed, // 完成
Failed, // 失败
Cancelled, // 取消
PartiallyCompleted // 部分完成(主轴线)
}
/// <summary>
/// 分支轴执行策略
/// </summary>
public enum BranchAxisStrategy
{
Parallel, // 纯并行
Priority, // 按优先级
Batch, // 分批并行
Sequential // 串行(特殊场景)
}
#endregion
#region 轴节点模型(最小业务单元)
/// <summary>
/// 轴节点参数基类
/// </summary>
public class AxisNodeParams
{
/// <summary>
/// 节点ID
/// </summary>
public string NodeId { get; set; } = Guid.NewGuid().ToString("N");
/// <summary>
/// 节点名称
/// </summary>
public string NodeName { get; set; }
/// <summary>
/// 节点类型
/// </summary>
public AxisNodeType NodeType { get; set; }
/// <summary>
/// 执行优先级(1-10,1最高)
/// </summary>
public int Priority { get; set; } = 5;
/// <summary>
/// 超时时间(秒)
/// </summary>
public int Timeout { get; set; } = 30;
/// <summary>
/// 重试次数
/// </summary>
public int RetryCount { get; set; } = 0;
/// <summary>
/// 重试间隔(毫秒)
/// </summary>
public int RetryInterval { get; set; } = 1000;
/// <summary>
/// 是否允许失败跳过(不影响整体)
/// </summary>
public bool AllowSkip { get; set; } = false;
/// <summary>
/// 业务参数(JSON格式)
/// </summary>
public string BusinessParams { get; set; } = "{}";
/// <summary>
/// 关联结构ID(产线/工单/工序ID)
/// </summary>
public string StructureId { get; set; }
/// <summary>
/// 关联结构类型
/// </summary>
public string StructureType { get; set; }
}
/// <summary>
/// 数据查询节点参数
/// </summary>
public class DataQueryNodeParams : AxisNodeParams
{
public DataQueryNodeParams() => NodeType = AxisNodeType.DataQuery;
/// <summary>
/// SQL语句
/// </summary>
public string Sql { get; set; }
/// <summary>
/// 查询参数
/// </summary>
public Dictionary<string, object> QueryParams { get; set; } = new();
/// <summary>
/// 是否返回数据
/// </summary>
public bool ReturnData { get; set; } = true;
}
/// <summary>
/// API调用节点参数
/// </summary>
public class ApiCallNodeParams : AxisNodeParams
{
public ApiCallNodeParams() => NodeType = AxisNodeType.ApiCall;
/// <summary>
/// API地址
/// </summary>
public string ApiUrl { get; set; }
/// <summary>
/// HTTP方法
/// </summary>
public string HttpMethod { get; set; } = "POST";
/// <summary>
/// 请求头
/// </summary>
public Dictionary<string, string> Headers { get; set; } = new();
/// <summary>
/// 请求体
/// </summary>
public string RequestBody { get; set; } = "{}";
}
/// <summary>
/// 轴节点执行结果
/// </summary>
public class AxisNodeExecutionResult
{
/// <summary>
/// 节点ID
/// </summary>
public string NodeId { get; set; }
/// <summary>
/// 执行状态
/// </summary>
public AxisExecutionStatus Status { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime EndTime { get; set; }
/// <summary>
/// 执行耗时(毫秒)
/// </summary>
public long ExecutionTimeMs => (long)(EndTime - StartTime).TotalMilliseconds;
/// <summary>
/// 结果数据(JSON格式)
/// </summary>
public string ResultData { get; set; }
/// <summary>
/// 错误信息
/// </summary>
public string ErrorMessage { get; set; }
/// <summary>
/// 实际重试次数
/// </summary>
public int ActualRetryCount { get; set; } = 0;
}
#endregion
#region 执行轴模型(组轴核心)
/// <summary>
/// 分支执行轴(独立业务段落)
/// </summary>
public class BranchExecutionAxis
{
/// <summary>
/// 分支轴ID
/// </summary>
public string BranchAxisId { get; set; } = Guid.NewGuid().ToString("N");
/// <summary>
/// 分支轴名称
/// </summary>
public string BranchAxisName { get; set; }
/// <summary>
/// 所属主轴线ID
/// </summary>
public string MasterAxisId { get; set; }
/// <summary>
/// 执行优先级
/// </summary>
public int Priority { get; set; } = 5;
/// <summary>
/// 包含的节点列表
/// </summary>
public List<AxisNodeParams> Nodes { get; set; } = new();
/// <summary>
/// 节点执行策略
/// </summary>
public BranchAxisStrategy NodeStrategy { get; set; } = BranchAxisStrategy.Parallel;
/// <summary>
/// 执行状态
/// </summary>
public AxisExecutionStatus Status { get; set; } = AxisExecutionStatus.Created;
/// <summary>
/// 执行结果
/// </summary>
public Dictionary<string, AxisNodeExecutionResult> NodeResults { get; set; } = new();
}
/// <summary>
/// 主执行轴(管控整体流程)
/// </summary>
public class MasterExecutionAxis
{
/// <summary>
/// 主轴线ID
/// </summary>
public string MasterAxisId { get; set; } = Guid.NewGuid().ToString("N");
/// <summary>
/// 主轴线名称
/// </summary>
public string MasterAxisName { get; set; }
/// <summary>
/// 业务场景(如:工单完工处理/生产数据同步)
/// </summary>
public string BusinessScenario { get; set; }
/// <summary>
/// 关联结构ID
/// </summary>
public string StructureId { get; set; }
/// <summary>
/// 关联结构类型
/// </summary>
public string StructureType { get; set; }
/// <summary>
/// 包含的分支轴列表
/// </summary>
public List<BranchExecutionAxis> BranchAxes { get; set; } = new();
/// <summary>
/// 分支轴执行策略
/// </summary>
public BranchAxisStrategy BranchStrategy { get; set; } = BranchAxisStrategy.Parallel;
/// <summary>
/// 执行状态
/// </summary>
public AxisExecutionStatus Status { get; set; } = AxisExecutionStatus.Created;
/// <summary>
/// 开始时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime EndTime { get; set; }
/// <summary>
/// 整体执行结果(组装后)
/// </summary>
public string AssembledResult { get; set; }
/// <summary>
/// 失败节点数
/// </summary>
public int FailedNodeCount { get; set; } = 0;
/// <summary>
/// 跳过节点数
/// </summary>
public int SkippedNodeCount { get; set; } = 0;
}
#endregion
2. 组轴式执行引擎(核心)
#region 轴节点执行器工厂
/// <summary>
/// 轴节点执行器基类
/// </summary>
public abstract class BaseAxisNodeExecutor
{
protected readonly AxisNodeParams _nodeParams;
protected readonly CancellationToken _cancellationToken;
protected readonly Action<string, int, AxisExecutionStatus> _progressAction;
protected AxisNodeExecutionResult _result = new();
protected BaseAxisNodeExecutor(AxisNodeParams nodeParams, CancellationToken cancellationToken,
Action<string, int, AxisExecutionStatus> progressAction = null)
{
_nodeParams = nodeParams;
_cancellationToken = cancellationToken;
_progressAction = progressAction;
_result.NodeId = nodeParams.NodeId;
}
/// <summary>
/// 执行节点(带重试/超时)
/// </summary>
/// <returns></returns>
public async Task<AxisNodeExecutionResult> ExecuteAsync()
{
_result.StartTime = DateTime.Now;
_progressAction?.Invoke(_nodeParams.NodeId, 0, AxisExecutionStatus.Running);
try
{
// 超时控制
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(_nodeParams.Timeout));
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(_cancellationToken, timeoutCts.Token);
// 重试逻辑
bool success = false;
int retryCount = 0;
while (retryCount <= _nodeParams.RetryCount && !success)
{
try
{
await ExecuteCoreAsync(linkedCts.Token);
success = true;
}
catch (OperationCanceledException)
{
_result.Status = AxisExecutionStatus.Cancelled;
_result.ErrorMessage = "执行取消/超时";
break;
}
catch (Exception ex)
{
retryCount++;
_result.ActualRetryCount = retryCount;
if (retryCount > _nodeParams.RetryCount) throw;
await Task.Delay(_nodeParams.RetryInterval, _cancellationToken);
}
}
if (success)
{
_result.Status = AxisExecutionStatus.Completed;
_progressAction?.Invoke(_nodeParams.NodeId, 100, AxisExecutionStatus.Completed);
}
}
catch (OperationCanceledException)
{
_result.Status = AxisExecutionStatus.Cancelled;
_result.ErrorMessage = "执行被取消";
_progressAction?.Invoke(_nodeParams.NodeId, 0, AxisExecutionStatus.Cancelled);
}
catch (Exception ex)
{
_result.Status = _nodeParams.AllowSkip ? AxisExecutionStatus.Skipped : AxisExecutionStatus.Failed;
_result.ErrorMessage = ex.Message;
_progressAction?.Invoke(_nodeParams.NodeId, 0, _result.Status);
}
finally
{
_result.EndTime = DateTime.Now;
}
return _result;
}
/// <summary>
/// 核心执行逻辑(子类实现)
/// </summary>
protected abstract Task ExecuteCoreAsync(CancellationToken cancellationToken);
/// <summary>
/// 更新进度
/// </summary>
protected void UpdateProgress(int progress)
{
_progressAction?.Invoke(_nodeParams.NodeId, progress, AxisExecutionStatus.Running);
}
}
/// <summary>
/// 数据查询节点执行器
/// </summary>
public class DataQueryNodeExecutor : BaseAxisNodeExecutor
{
private readonly IDbConnection _dbConnection;
public DataQueryNodeExecutor(DataQueryNodeParams nodeParams, IDbConnection dbConnection,
CancellationToken cancellationToken, Action<string, int, AxisExecutionStatus> progressAction = null)
: base(nodeParams, cancellationToken, progressAction)
{
_dbConnection = dbConnection;
}
protected override async Task ExecuteCoreAsync(CancellationToken cancellationToken)
{
var param = (DataQueryNodeParams)_nodeParams;
UpdateProgress(20);
if (_dbConnection.State != ConnectionState.Open)
await _dbConnection.OpenAsync(cancellationToken);
UpdateProgress(40);
var data = await _dbConnection.QueryAsync<dynamic>(param.Sql, param.QueryParams, cancellationToken: cancellationToken);
UpdateProgress(80);
if (param.ReturnData)
_result.ResultData = JsonConvert.SerializeObject(data);
UpdateProgress(100);
}
}
/// <summary>
/// API调用节点执行器
/// </summary>
public class ApiCallNodeExecutor : BaseAxisNodeExecutor
{
private readonly HttpClient _httpClient;
public ApiCallNodeExecutor(ApiCallNodeParams nodeParams, HttpClient httpClient,
CancellationToken cancellationToken, Action<string, int, AxisExecutionStatus> progressAction = null)
: base(nodeParams, cancellationToken, progressAction)
{
_httpClient = httpClient;
}
protected override async Task ExecuteCoreAsync(CancellationToken cancellationToken)
{
var param = (ApiCallNodeParams)_nodeParams;
UpdateProgress(20);
var request = new HttpRequestMessage(new HttpMethod(param.HttpMethod), param.ApiUrl);
foreach (var header in param.Headers)
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
UpdateProgress(40);
if (!string.IsNullOrEmpty(param.RequestBody) && (param.HttpMethod == "POST" || param.HttpMethod == "PUT"))
request.Content = new StringContent(param.RequestBody, Encoding.UTF8, "application/json");
UpdateProgress(60);
var response = await _httpClient.SendAsync(request, cancellationToken);
response.EnsureSuccessStatusCode();
UpdateProgress(80);
_result.ResultData = await response.Content.ReadAsStringAsync(cancellationToken);
UpdateProgress(100);
}
}
/// <summary>
/// 轴节点执行器工厂
/// </summary>
public class AxisNodeExecutorFactory
{
private readonly IDbConnection _dbConnection;
private readonly HttpClient _httpClient;
public AxisNodeExecutorFactory(IDbConnection dbConnection, HttpClient httpClient)
{
_dbConnection = dbConnection;
_httpClient = httpClient;
}
/// <summary>
/// 创建执行器
/// </summary>
public BaseAxisNodeExecutor CreateExecutor(AxisNodeParams nodeParams, CancellationToken cancellationToken,
Action<string, int, AxisExecutionStatus> progressAction = null)
{
return nodeParams switch
{
DataQueryNodeParams queryParam => new DataQueryNodeExecutor(queryParam, _dbConnection, cancellationToken, progressAction),
ApiCallNodeParams apiParam => new ApiCallNodeExecutor(apiParam, _httpClient, cancellationToken, progressAction),
_ => throw new NotSupportedException($"不支持的节点类型:{nodeParams.NodeType}")
};
}
}
#endregion
#region 组轴式执行引擎(核心调度)
/// <summary>
/// 组轴式多线程执行引擎
/// 核心功能:主/分支轴调度、多结构并发控制、结果组装
/// </summary>
public class AxisGroupExecutorEngine : IDisposable
{
// 单例实例
private static readonly Lazy<AxisGroupExecutorEngine> _instance = new(() => new AxisGroupExecutorEngine());
public static AxisGroupExecutorEngine Instance => _instance.Value;
// 执行器工厂
private readonly AxisNodeExecutorFactory _executorFactory;
// 多结构并发控制(按结构类型隔离信号量)
private readonly ConcurrentDictionary<string, SemaphoreSlim> _structureSemaphores = new();
// 执行中的主轴线
private readonly ConcurrentDictionary<string, MasterExecutionAxis> _runningMasterAxes = new();
// 取消令牌源(按主轴线ID)
private readonly ConcurrentDictionary<string, CancellationTokenSource> _masterCtsDict = new();
// 事件定义
public event Action<string, int, AxisExecutionStatus> NodeProgressUpdated;
public event Action<string, AxisExecutionStatus> AxisStatusUpdated;
public event Action<string, string> MasterAxisCompleted;
/// <summary>
/// 私有构造函数
/// </summary>
private AxisGroupExecutorEngine()
{
// 初始化数据库连接和HttpClient
var dbConn = new SqlConnection(ConfigurationManager.ConnectionStrings["MESDB"].ConnectionString);
var httpClient = new HttpClient { Timeout = TimeSpan.FromMinutes(5) };
_executorFactory = new AxisNodeExecutorFactory(dbConn, httpClient);
// 初始化默认结构类型的并发控制
var defaultStructures = new[] { "Line", "WorkOrder", "Process", "Station" };
foreach (var structure in defaultStructures)
_structureSemaphores.TryAdd(structure, new SemaphoreSlim(5, 50)); // 默认最大并发5
}
/// <summary>
/// 设置结构类型最大并发数
/// </summary>
public void SetStructureMaxConcurrent(string structureType, int maxConcurrent)
{
_structureSemaphores.AddOrUpdate(structureType,
_ => new SemaphoreSlim(maxConcurrent, maxConcurrent),
(_, old) => new SemaphoreSlim(maxConcurrent, maxConcurrent));
}
/// <summary>
/// 执行主轴线(核心入口)
/// </summary>
public async Task ExecuteMasterAxisAsync(MasterExecutionAxis masterAxis)
{
if (_runningMasterAxes.ContainsKey(masterAxis.MasterAxisId))
throw new InvalidOperationException($"主轴线{masterAxis.MasterAxisId}已在执行中");
// 初始化
masterAxis.StartTime = DateTime.Now;
masterAxis.Status = AxisExecutionStatus.Running;
_runningMasterAxes[masterAxis.MasterAxisId] = masterAxis;
_masterCtsDict[masterAxis.MasterAxisId] = new CancellationTokenSource();
var masterCts = _masterCtsDict[masterAxis.MasterAxisId];
// 触发状态更新事件
AxisStatusUpdated?.Invoke(masterAxis.MasterAxisId, AxisExecutionStatus.Running);
try
{
// 执行所有分支轴
await ExecuteBranchAxesAsync(masterAxis, masterCts.Token);
// 组装执行结果
masterAxis.AssembledResult = AssembleMasterAxisResult(masterAxis);
// 统计失败/跳过节点
masterAxis.FailedNodeCount = masterAxis.BranchAxes
.Sum(b => b.NodeResults.Values.Count(r => r.Status == AxisExecutionStatus.Failed));
masterAxis.SkippedNodeCount = masterAxis.BranchAxes
.Sum(b => b.NodeResults.Values.Count(r => r.Status == AxisExecutionStatus.Skipped));
// 更新主轴线状态
masterAxis.Status = masterAxis.FailedNodeCount > 0
? AxisExecutionStatus.PartiallyCompleted
: AxisExecutionStatus.Completed;
masterAxis.EndTime = DateTime.Now;
// 触发完成事件
MasterAxisCompleted?.Invoke(masterAxis.MasterAxisId, masterAxis.AssembledResult);
}
catch (OperationCanceledException)
{
masterAxis.Status = AxisExecutionStatus.Cancelled;
masterAxis.EndTime = DateTime.Now;
AxisStatusUpdated?.Invoke(masterAxis.MasterAxisId, AxisExecutionStatus.Cancelled);
}
catch (Exception ex)
{
masterAxis.Status = AxisExecutionStatus.Failed;
masterAxis.EndTime = DateTime.Now;
AxisStatusUpdated?.Invoke(masterAxis.MasterAxisId, AxisExecutionStatus.Failed);
throw new Exception($"主轴线执行失败:{ex.Message}", ex);
}
finally
{
// 清理资源
_runningMasterAxes.TryRemove(masterAxis.MasterAxisId, out _);
if (_masterCtsDict.TryRemove(masterAxis.MasterAxisId, out var cts))
cts.Dispose();
}
}
/// <summary>
/// 执行分支轴
/// </summary>
private async Task ExecuteBranchAxesAsync(MasterExecutionAxis masterAxis, CancellationToken cancellationToken)
{
var branchAxes = masterAxis.BranchAxes.OrderBy(b => b.Priority).ToList();
var branchTasks = new List<Task>();
// 根据分支轴执行策略处理
switch (masterAxis.BranchStrategy)
{
case BranchAxisStrategy.Parallel:
// 所有分支轴并行执行
foreach (var branchAxis in branchAxes)
branchTasks.Add(ExecuteSingleBranchAxisAsync(branchAxis, masterAxis.StructureType, cancellationToken));
await Task.WhenAll(branchTasks);
break;
case BranchAxisStrategy.Priority:
// 按优先级串行执行分支轴(同优先级并行)
var priorityGroups = branchAxes.GroupBy(b => b.Priority).OrderBy(g => g.Key);
foreach (var group in priorityGroups)
{
var groupTasks = group.Select(b => ExecuteSingleBranchAxisAsync(b, masterAxis.StructureType, cancellationToken)).ToList();
await Task.WhenAll(groupTasks);
}
break;
case BranchAxisStrategy.Batch:
// 分批执行(每批5个)
foreach (var batch in branchAxes.Chunk(5))
{
var batchTasks = batch.Select(b => ExecuteSingleBranchAxisAsync(b, masterAxis.StructureType, cancellationToken)).ToList();
await Task.WhenAll(batchTasks);
}
break;
case BranchAxisStrategy.Sequential:
// 完全串行
foreach (var branchAxis in branchAxes)
await ExecuteSingleBranchAxisAsync(branchAxis, masterAxis.StructureType, cancellationToken);
break;
}
}
/// <summary>
/// 执行单个分支轴
/// </summary>
private async Task ExecuteSingleBranchAxisAsync(BranchExecutionAxis branchAxis, string structureType, CancellationToken cancellationToken)
{
// 更新分支轴状态
branchAxis.Status = AxisExecutionStatus.Running;
AxisStatusUpdated?.Invoke(branchAxis.BranchAxisId, AxisExecutionStatus.Running);
try
{
// 获取结构类型的并发信号量
var semaphore = _structureSemaphores.GetOrAdd(structureType, _ => new SemaphoreSlim(5, 50));
await semaphore.WaitAsync(cancellationToken);
// 执行分支轴内的节点
await ExecuteBranchAxisNodesAsync(branchAxis, cancellationToken);
}
finally
{
// 释放信号量
_structureSemaphores.TryGetValue(structureType, out var semaphore);
semaphore?.Release();
// 更新分支轴最终状态
branchAxis.Status = branchAxis.NodeResults.Values.Any(r => r.Status == AxisExecutionStatus.Failed)
? AxisExecutionStatus.Failed
: AxisExecutionStatus.Completed;
AxisStatusUpdated?.Invoke(branchAxis.BranchAxisId, branchAxis.Status);
}
}
/// <summary>
/// 执行分支轴内的节点
/// </summary>
private async Task ExecuteBranchAxisNodesAsync(BranchExecutionAxis branchAxis, CancellationToken cancellationToken)
{
var nodeTasks = new List<Task>();
branchAxis.NodeResults = new Dictionary<string, AxisNodeExecutionResult>();
// 根据节点执行策略处理
switch (branchAxis.NodeStrategy)
{
case BranchAxisStrategy.Parallel:
foreach (var node in branchAxis.Nodes)
nodeTasks.Add(ExecuteSingleNodeAsync(node, cancellationToken, branchAxis));
await Task.WhenAll(nodeTasks);
break;
case BranchAxisStrategy.Priority:
var priorityGroups = branchAxis.Nodes.GroupBy(n => n.Priority).OrderBy(g => g.Key);
foreach (var group in priorityGroups)
{
var groupTasks = group.Select(n => ExecuteSingleNodeAsync(n, cancellationToken, branchAxis)).ToList();
await Task.WhenAll(groupTasks);
}
break;
default:
foreach (var node in branchAxis.Nodes)
await ExecuteSingleNodeAsync(node, cancellationToken, branchAxis);
break;
}
}
/// <summary>
/// 执行单个节点
/// </summary>
private async Task ExecuteSingleNodeAsync(AxisNodeParams nodeParams, CancellationToken cancellationToken, BranchExecutionAxis branchAxis)
{
try
{
// 创建节点执行器
var executor = _executorFactory.CreateExecutor(nodeParams, cancellationToken,
(nodeId, progress, status) =>
{
NodeProgressUpdated?.Invoke(nodeId, progress, status);
});
// 执行节点
var result = await executor.ExecuteAsync();
branchAxis.NodeResults[nodeParams.NodeId] = result;
}
catch (Exception ex)
{
// 记录节点执行异常
branchAxis.NodeResults[nodeParams.NodeId] = new AxisNodeExecutionResult
{
NodeId = nodeParams.NodeId,
Status = AxisExecutionStatus.Failed,
StartTime = DateTime.Now,
EndTime = DateTime.Now,
ErrorMessage = ex.Message
};
}
}
/// <summary>
/// 组装主轴线执行结果
/// </summary>
private string AssembleMasterAxisResult(MasterExecutionAxis masterAxis)
{
var assembleResult = new
{
MasterAxisId = masterAxis.MasterAxisId,
MasterAxisName = masterAxis.MasterAxisName,
BusinessScenario = masterAxis.BusinessScenario,
ExecutionTimeMs = (long)(masterAxis.EndTime - masterAxis.StartTime).TotalMilliseconds,
Status = masterAxis.Status,
FailedNodeCount = masterAxis.FailedNodeCount,
SkippedNodeCount = masterAxis.SkippedNodeCount,
BranchAxes = masterAxis.BranchAxes.Select(b => new
{
b.BranchAxisId,
b.BranchAxisName,
b.Status,
NodeCount = b.Nodes.Count,
CompletedNodeCount = b.NodeResults.Values.Count(r => r.Status == AxisExecutionStatus.Completed),
Nodes = b.NodeResults.Select(n => new
{
n.Key,
n.Value.Status,
n.Value.ExecutionTimeMs,
n.Value.ResultData,
n.Value.ErrorMessage
})
})
};
return JsonConvert.SerializeObject(assembleResult, Formatting.Indented);
}
/// <summary>
/// 取消主轴线执行
/// </summary>
public void CancelMasterAxis(string masterAxisId)
{
if (_masterCtsDict.TryGetValue(masterAxisId, out var cts))
{
cts.Cancel();
AxisStatusUpdated?.Invoke(masterAxisId, AxisExecutionStatus.Cancelled);
}
}
/// <summary>
/// 获取主轴线执行状态
/// </summary>
public MasterExecutionAxis GetMasterAxisStatus(string masterAxisId)
{
_runningMasterAxes.TryGetValue(masterAxisId, out var masterAxis);
return masterAxis;
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
// 取消所有执行中的主轴线
foreach (var cts in _masterCtsDict.Values)
{
cts.Cancel();
cts.Dispose();
}
// 释放信号量
foreach (var semaphore in _structureSemaphores.Values)
semaphore.Dispose();
_runningMasterAxes.Clear();
_masterCtsDict.Clear();
_structureSemaphores.Clear();
}
}
#endregion
3. 可视化界面组件(WinForm)
/// <summary>
/// 组轴式执行管理界面
/// </summary>
public partial class AxisGroupExecutorForm : Form
{
// 执行引擎
private readonly AxisGroupExecutorEngine _engine = AxisGroupExecutorEngine.Instance;
// 当前主轴线
private MasterExecutionAxis _currentMasterAxis;
public AxisGroupExecutorForm()
{
InitializeComponent();
RegisterEvents();
InitUI();
}
/// <summary>
/// 注册事件
/// </summary>
private void RegisterEvents()
{
_engine.NodeProgressUpdated += OnNodeProgressUpdated;
_engine.AxisStatusUpdated += OnAxisStatusUpdated;
_engine.MasterAxisCompleted += OnMasterAxisCompleted;
}
/// <summary>
/// 初始化UI
/// </summary>
private void InitUI()
{
// 结构类型下拉框
cboStructureType.Items.AddRange(new[] { "Line", "WorkOrder", "Process", "Station" });
cboStructureType.SelectedIndex = 0;
// 业务场景下拉框
cboBusinessScenario.Items.AddRange(new[] { "工单完工处理", "生产数据同步", "ERP数据推送", "设备状态采集" });
cboBusinessScenario.SelectedIndex = 0;
// 分支轴策略下拉框
cboBranchStrategy.Items.AddRange(Enum.GetNames(typeof(BranchAxisStrategy)));
cboBranchStrategy.SelectedIndex = 0;
// 节点类型下拉框
cboNodeType.Items.AddRange(Enum.GetNames(typeof(AxisNodeType)));
cboNodeType.SelectedIndex = 0;
// 初始化主轴线列表
dgvMasterAxes.Columns.AddRange(new DataGridViewColumn[]
{
new DataGridViewTextBoxColumn { Name = "MasterAxisId", HeaderText = "主轴线ID", Width = 150 },
new DataGridViewTextBoxColumn { Name = "MasterAxisName", HeaderText = "主轴线名称", Width = 150 },
new DataGridViewTextBoxColumn { Name = "BusinessScenario", HeaderText = "业务场景", Width = 120 },
new DataGridViewTextBoxColumn { Name = "StructureType", HeaderText = "结构类型", Width = 100 },
new DataGridViewTextBoxColumn { Name = "StructureId", HeaderText = "结构ID", Width = 100 },
new DataGridViewTextBoxColumn { Name = "Status", HeaderText = "状态", Width = 100 },
new DataGridViewTextBoxColumn { Name = "StartTime", HeaderText = "开始时间", Width = 180 },
new DataGridViewTextBoxColumn { Name = "EndTime", HeaderText = "结束时间", Width = 180 }
});
// 初始化分支轴列表
dgvBranchAxes.Columns.AddRange(new DataGridViewColumn[]
{
new DataGridViewTextBoxColumn { Name = "BranchAxisId", HeaderText = "分支轴ID", Width = 150 },
new DataGridViewTextBoxColumn { Name = "BranchAxisName", HeaderText = "分支轴名称", Width = 150 },
new DataGridViewTextBoxColumn { Name = "Priority", HeaderText = "优先级", Width = 80 },
new DataGridViewTextBoxColumn { Name = "NodeCount", HeaderText = "节点数", Width = 80 },
new DataGridViewTextBoxColumn { Name = "Status", HeaderText = "状态", Width = 100 }
});
// 初始化节点列表
dgvNodes.Columns.AddRange(new DataGridViewColumn[]
{
new DataGridViewTextBoxColumn { Name = "NodeId", HeaderText = "节点ID", Width = 150 },
new DataGridViewTextBoxColumn { Name = "NodeName", HeaderText = "节点名称", Width = 150 },
new DataGridViewTextBoxColumn { Name = "NodeType", HeaderText = "节点类型", Width = 100 },
new DataGridViewTextBoxColumn { Name = "Priority", HeaderText = "优先级", Width = 80 },
new DataGridViewTextBoxColumn { Name = "Status", HeaderText = "状态", Width = 100 },
new DataGridViewTextBoxColumn { Name = "Progress", HeaderText = "进度", Width = 80 },
new DataGridViewTextBoxColumn { Name = "ExecutionTime", HeaderText = "耗时(ms)", Width = 100 },
new DataGridViewTextBoxColumn { Name = "ErrorMessage", HeaderText = "错误信息", Width = 200 }
});
// 按钮事件绑定
btnCreateMasterAxis.Click += BtnCreateMasterAxis_Click;
btnAddBranchAxis.Click += BtnAddBranchAxis_Click;
btnAddNode.Click += BtnAddNode_Click;
btnExecuteMasterAxis.Click += BtnExecuteMasterAxis_Click;
btnCancelMasterAxis.Click += BtnCancelMasterAxis_Click;
btnSetMaxConcurrent.Click += BtnSetMaxConcurrent_Click;
}
#region UI事件处理
/// <summary>
/// 创建主轴线
/// </summary>
private void BtnCreateMasterAxis_Click(object sender, EventArgs e)
{
try
{
_currentMasterAxis = new MasterExecutionAxis
{
MasterAxisName = txtMasterAxisName.Text,
BusinessScenario = cboBusinessScenario.SelectedItem.ToString(),
StructureType = cboStructureType.SelectedItem.ToString(),
StructureId = txtStructureId.Text,
BranchStrategy = (BranchAxisStrategy)Enum.Parse(typeof(BranchAxisStrategy), cboBranchStrategy.SelectedItem.ToString())
};
// 添加到主轴线列表
var row = dgvMasterAxes.Rows.Add();
row.Cells["MasterAxisId"].Value = _currentMasterAxis.MasterAxisId;
row.Cells["MasterAxisName"].Value = _currentMasterAxis.MasterAxisName;
row.Cells["BusinessScenario"].Value = _currentMasterAxis.BusinessScenario;
row.Cells["StructureType"].Value = _currentMasterAxis.StructureType;
row.Cells["StructureId"].Value = _currentMasterAxis.StructureId;
row.Cells["Status"].Value = _currentMasterAxis.Status.ToString();
row.Cells["StartTime"].Value = "";
row.Cells["EndTime"].Value = "";
// 保存主轴线到行Tag
row.Tag = _currentMasterAxis;
MessageBox.Show($"主轴线创建成功:{_currentMasterAxis.MasterAxisId}", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"创建主轴线失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 添加分支轴
/// </summary>
private void BtnAddBranchAxis_Click(object sender, EventArgs e)
{
if (_currentMasterAxis == null)
{
MessageBox.Show("请先创建主轴线", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
var branchAxis = new BranchExecutionAxis
{
BranchAxisName = txtBranchAxisName.Text,
MasterAxisId = _currentMasterAxis.MasterAxisId,
Priority = (int)nudBranchPriority.Value,
NodeStrategy = (BranchAxisStrategy)Enum.Parse(typeof(BranchAxisStrategy), cboNodeStrategy.SelectedItem.ToString())
};
// 添加到主轴线
_currentMasterAxis.BranchAxes.Add(branchAxis);
// 添加到分支轴列表
var row = dgvBranchAxes.Rows.Add();
row.Cells["BranchAxisId"].Value = branchAxis.BranchAxisId;
row.Cells["BranchAxisName"].Value = branchAxis.BranchAxisName;
row.Cells["Priority"].Value = branchAxis.Priority;
row.Cells["NodeCount"].Value = 0;
row.Cells["Status"].Value = branchAxis.Status.ToString();
// 保存分支轴到行Tag
row.Tag = branchAxis;
MessageBox.Show($"分支轴添加成功:{branchAxis.BranchAxisId}", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"添加分支轴失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 添加节点
/// </summary>
private void BtnAddNode_Click(object sender, EventArgs e)
{
if (dgvBranchAxes.SelectedRows.Count == 0)
{
MessageBox.Show("请选择要添加节点的分支轴", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
var selectedRow = dgvBranchAxes.SelectedRows[0];
var branchAxis = selectedRow.Tag as BranchExecutionAxis;
if (branchAxis == null) return;
// 创建节点参数
AxisNodeParams nodeParams = null;
var nodeType = (AxisNodeType)Enum.Parse(typeof(AxisNodeType), cboNodeType.SelectedItem.ToString());
switch (nodeType)
{
case AxisNodeType.DataQuery:
nodeParams = new DataQueryNodeParams
{
NodeName = txtNodeName.Text,
Priority = (int)nudNodePriority.Value,
Timeout = (int)nudNodeTimeout.Value,
RetryCount = (int)nudNodeRetryCount.Value,
AllowSkip = chkNodeAllowSkip.Checked,
StructureType = _currentMasterAxis.StructureType,
StructureId = _currentMasterAxis.StructureId,
Sql = txtSql.Text,
QueryParams = new Dictionary<string, object> { { "StructureId", _currentMasterAxis.StructureId } }
};
break;
case AxisNodeType.ApiCall:
nodeParams = new ApiCallNodeParams
{
NodeName = txtNodeName.Text,
Priority = (int)nudNodePriority.Value,
Timeout = (int)nudNodeTimeout.Value,
RetryCount = (int)nudNodeRetryCount.Value,
AllowSkip = chkNodeAllowSkip.Checked,
StructureType = _currentMasterAxis.StructureType,
StructureId = _currentMasterAxis.StructureId,
ApiUrl = txtApiUrl.Text,
HttpMethod = cboHttpMethod.SelectedItem.ToString(),
RequestBody = txtRequestBody.Text
};
break;
default:
MessageBox.Show("暂不支持该节点类型", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// 添加到分支轴
branchAxis.Nodes.Add(nodeParams);
// 更新分支轴节点数
selectedRow.Cells["NodeCount"].Value = branchAxis.Nodes.Count;
// 添加到节点列表
var row = dgvNodes.Rows.Add();
row.Cells["NodeId"].Value = nodeParams.NodeId;
row.Cells["NodeName"].Value = nodeParams.NodeName;
row.Cells["NodeType"].Value = nodeParams.NodeType.ToString();
row.Cells["Priority"].Value = nodeParams.Priority;
row.Cells["Status"].Value = AxisExecutionStatus.Created.ToString();
row.Cells["Progress"].Value = "0%";
row.Cells["ExecutionTime"].Value = "";
row.Cells["ErrorMessage"].Value = "";
// 保存节点到行Tag
row.Tag = new { BranchAxisId = branchAxis.BranchAxisId, NodeParams = nodeParams };
MessageBox.Show($"节点添加成功:{nodeParams.NodeId}", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"添加节点失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 执行主轴线
/// </summary>
private async void BtnExecuteMasterAxis_Click(object sender, EventArgs e)
{
if (_currentMasterAxis == null)
{
MessageBox.Show("请先创建主轴线", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
// 更新主轴线开始时间
foreach (DataGridViewRow row in dgvMasterAxes.Rows)
{
if (row.Cells["MasterAxisId"].Value.ToString() == _currentMasterAxis.MasterAxisId)
{
row.Cells["Status"].Value = AxisExecutionStatus.Running.ToString();
row.Cells["StartTime"].Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
break;
}
}
// 异步执行主轴线
await Task.Run(async () =>
{
await _engine.ExecuteMasterAxisAsync(_currentMasterAxis);
});
// 更新主轴线状态
foreach (DataGridViewRow row in dgvMasterAxes.Rows)
{
if (row.Cells["MasterAxisId"].Value.ToString() == _currentMasterAxis.MasterAxisId)
{
row.Cells["Status"].Value = _currentMasterAxis.Status.ToString();
row.Cells["EndTime"].Value = _currentMasterAxis.EndTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
// 根据状态设置行颜色
row.DefaultCellStyle.BackColor = _currentMasterAxis.Status switch
{
AxisExecutionStatus.Completed => Color.LightGreen,
AxisExecutionStatus.Failed => Color.LightPink,
AxisExecutionStatus.Cancelled => Color.LightGray,
AxisExecutionStatus.PartiallyCompleted => Color.LightYellow,
_ => Color.White
};
break;
}
}
MessageBox.Show($"主轴线执行完成:{_currentMasterAxis.Status}", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"执行主轴线失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 取消主轴线执行
/// </summary>
private void BtnCancelMasterAxis_Click(object sender, EventArgs e)
{
if (_currentMasterAxis == null)
{
MessageBox.Show("请先创建并执行主轴线", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
_engine.CancelMasterAxis(_currentMasterAxis.MasterAxisId);
MessageBox.Show("主轴线取消请求已提交", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"取消主轴线失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 设置最大并发数
/// </summary>
private void BtnSetMaxConcurrent_Click(object sender, EventArgs e)
{
try
{
var structureType = cboStructureType.SelectedItem.ToString();
var maxConcurrent = (int)nudMaxConcurrent.Value;
_engine.SetStructureMaxConcurrent(structureType, maxConcurrent);
MessageBox.Show($"结构类型{structureType}最大并发数已设置为{maxConcurrent}",
"成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"设置最大并发数失败:{ex.Message}",
"错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 节点进度更新
/// </summary>
private void OnNodeProgressUpdated(string nodeId, int progress, AxisExecutionStatus status)
{
if (dgvNodes.InvokeRequired)
{
dgvNodes.Invoke(new Action(() => UpdateNodeProgress(nodeId, progress, status)));
}
else
{
UpdateNodeProgress(nodeId, progress, status);
}
}
/// <summary>
/// 更新节点进度UI
/// </summary>
private void UpdateNodeProgress(string nodeId, int progress, AxisExecutionStatus status)
{
foreach (DataGridViewRow row in dgvNodes.Rows)
{
if (row.Cells["NodeId"].Value?.ToString() == nodeId)
{
row.Cells["Status"].Value = status.ToString();
row.Cells["Progress"].Value = $"{progress}%";
// 设置行颜色
row.DefaultCellStyle.BackColor = status switch
{
AxisExecutionStatus.Running => Color.LightYellow,
AxisExecutionStatus.Completed => Color.LightGreen,
AxisExecutionStatus.Failed => Color.LightPink,
AxisExecutionStatus.Skipped => Color.LightBlue,
AxisExecutionStatus.Cancelled => Color.LightGray,
_ => Color.White
};
// 如果执行完成,更新耗时
if (status is AxisExecutionStatus.Completed or AxisExecutionStatus.Failed or AxisExecutionStatus.Skipped or AxisExecutionStatus.Cancelled)
{
// 查找节点结果
var nodeTag = row.Tag as dynamic;
var branchAxis = _currentMasterAxis.BranchAxes.FirstOrDefault(b => b.BranchAxisId == nodeTag.BranchAxisId);
if (branchAxis != null && branchAxis.NodeResults.TryGetValue(nodeId, out var result))
{
row.Cells["ExecutionTime"].Value = result.ExecutionTimeMs;
row.Cells["ErrorMessage"].Value = result.ErrorMessage;
}
}
break;
}
}
}
/// <summary>
/// 轴状态更新
/// </summary>
private void OnAxisStatusUpdated(string axisId, AxisExecutionStatus status)
{
// 更新分支轴状态
if (dgvBranchAxes.InvokeRequired)
{
dgvBranchAxes.Invoke(new Action(() => UpdateBranchAxisStatus(axisId, status)));
}
else
{
UpdateBranchAxisStatus(axisId, status);
}
}
/// <summary>
/// 更新分支轴状态UI
/// </summary>
private void UpdateBranchAxisStatus(string branchAxisId, AxisExecutionStatus status)
{
foreach (DataGridViewRow row in dgvBranchAxes.Rows)
{
if (row.Cells["BranchAxisId"].Value?.ToString() == branchAxisId)
{
row.Cells["Status"].Value = status.ToString();
// 设置行颜色
row.DefaultCellStyle.BackColor = status switch
{
AxisExecutionStatus.Running => Color.LightYellow,
AxisExecutionStatus.Completed => Color.LightGreen,
AxisExecutionStatus.Failed => Color.LightPink,
AxisExecutionStatus.Cancelled => Color.LightGray,
_ => Color.White
};
break;
}
}
}
/// <summary>
/// 主轴线完成事件
/// </summary>
private void OnMasterAxisCompleted(string masterAxisId, string assembledResult)
{
if (InvokeRequired)
{
Invoke(new Action(() =>
{
// 显示组装结果
txtAssembledResult.Text = assembledResult;
}));
}
else
{
txtAssembledResult.Text = assembledResult;
}
}
#endregion
/// <summary>
/// 窗体关闭时清理资源
/// </summary>
private void AxisGroupExecutorForm_FormClosing(object sender, FormClosingEventArgs e)
{
_engine.Dispose();
}
}
4. API 接口组件
/// <summary>
/// 组轴式执行引擎API控制器
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class AxisGroupExecutorController : ControllerBase
{
private readonly AxisGroupExecutorEngine _engine = AxisGroupExecutorEngine.Instance;
private readonly ILogger<AxisGroupExecutorController> _logger;
public AxisGroupExecutorController(ILogger<AxisGroupExecutorController> logger)
{
_logger = logger;
}
/// <summary>
/// 创建并执行主轴线
/// </summary>
[HttpPost("execute-master-axis")]
public async Task<IActionResult> ExecuteMasterAxis([FromBody] MasterAxisRequest request)
{
try
{
// 转换请求到主轴线模型
var masterAxis = ConvertToMasterAxis(request);
if (masterAxis == null)
return BadRequest("无效的主轴线参数");
// 异步执行主轴线
_ = Task.Run(async () =>
{
await _engine.ExecuteMasterAxisAsync(masterAxis);
});
_logger.LogInformation($"主轴线{masterAxis.MasterAxisId}已提交执行");
return Ok(new
{
Success = true,
MasterAxisId = masterAxis.MasterAxisId,
Message = "主轴线已提交执行"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "创建并执行主轴线失败");
return StatusCode(500, new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 获取主轴线执行状态
/// </summary>
[HttpGet("master-axis/{masterAxisId}")]
public IActionResult GetMasterAxisStatus(string masterAxisId)
{
try
{
var masterAxis = _engine.GetMasterAxisStatus(masterAxisId);
if (masterAxis == null)
return NotFound(new { Success = false, Message = "主轴线不存在" });
return Ok(new
{
Success = true,
Data = new
{
masterAxis.MasterAxisId,
masterAxis.MasterAxisName,
masterAxis.BusinessScenario,
masterAxis.StructureType,
masterAxis.StructureId,
masterAxis.Status,
masterAxis.StartTime,
masterAxis.EndTime,
masterAxis.FailedNodeCount,
masterAxis.SkippedNodeCount,
BranchAxesCount = masterAxis.BranchAxes.Count
}
});
}
catch (Exception ex)
{
_logger.LogError(ex, $"获取主轴线{masterAxisId}状态失败");
return StatusCode(500, new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 取消主轴线执行
/// </summary>
[HttpPost("master-axis/{masterAxisId}/cancel")]
public IActionResult CancelMasterAxis(string masterAxisId)
{
try
{
_engine.CancelMasterAxis(masterAxisId);
_logger.LogInformation($"主轴线{masterAxisId}取消请求已提交");
return Ok(new { Success = true, Message = "主轴线取消请求已提交" });
}
catch (Exception ex)
{
_logger.LogError(ex, $"取消主轴线{masterAxisId}失败");
return StatusCode(500, new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 设置结构类型最大并发数
/// </summary>
[HttpPost("structure/{structureType}/max-concurrent/{maxConcurrent}")]
public IActionResult SetStructureMaxConcurrent(string structureType, int maxConcurrent)
{
try
{
_engine.SetStructureMaxConcurrent(structureType, maxConcurrent);
_logger.LogInformation($"结构类型{structureType}最大并发数设置为{maxConcurrent}");
return Ok(new
{
Success = true,
Message = $"结构类型{structureType}最大并发数已设置为{maxConcurrent}"
});
}
catch (Exception ex)
{
_logger.LogError(ex, $"设置结构类型{structureType}最大并发数失败");
return StatusCode(500, new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 转换请求模型到主轴线
/// </summary>
private MasterExecutionAxis ConvertToMasterAxis(MasterAxisRequest request)
{
var masterAxis = new MasterExecutionAxis
{
MasterAxisName = request.MasterAxisName,
BusinessScenario = request.BusinessScenario,
StructureType = request.StructureType,
StructureId = request.StructureId,
BranchStrategy = request.BranchStrategy
};
// 转换分支轴
if (request.BranchAxes != null)
{
foreach (var branchReq in request.BranchAxes)
{
var branchAxis = new BranchExecutionAxis
{
BranchAxisName = branchReq.BranchAxisName,
Priority = branchReq.Priority ?? 5,
NodeStrategy = branchReq.NodeStrategy ?? BranchAxisStrategy.Parallel
};
// 转换节点
if (branchReq.Nodes != null)
{
foreach (var nodeReq in branchReq.Nodes)
{
AxisNodeParams nodeParams = nodeReq.NodeType switch
{
"DataQuery" => new DataQueryNodeParams
{
NodeName = nodeReq.NodeName,
Priority = nodeReq.Priority ?? 5,
Timeout = nodeReq.Timeout ?? 30,
RetryCount = nodeReq.RetryCount ?? 0,
AllowSkip = nodeReq.AllowSkip ?? false,
Sql = nodeReq.BusinessParams?["Sql"]?.ToString(),
QueryParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(
nodeReq.BusinessParams?["QueryParams"]?.ToString() ?? "{}")
},
"ApiCall" => new ApiCallNodeParams
{
NodeName = nodeReq.NodeName,
Priority = nodeReq.Priority ?? 5,
Timeout = nodeReq.Timeout ?? 30,
RetryCount = nodeReq.RetryCount ?? 0,
AllowSkip = nodeReq.AllowSkip ?? false,
ApiUrl = nodeReq.BusinessParams?["ApiUrl"]?.ToString(),
HttpMethod = nodeReq.BusinessParams?["HttpMethod"]?.ToString() ?? "POST",
RequestBody = nodeReq.BusinessParams?["RequestBody"]?.ToString() ?? "{}"
},
_ => null
};
if (nodeParams != null)
branchAxis.Nodes.Add(nodeParams);
}
}
masterAxis.BranchAxes.Add(branchAxis);
}
}
return masterAxis;
}
}
#region API请求模型
/// <summary>
/// 主轴线请求模型
/// </summary>
public class MasterAxisRequest
{
public string MasterAxisName { get; set; }
public string BusinessScenario { get; set; }
public string StructureType { get; set; }
public string StructureId { get; set; }
public BranchAxisStrategy BranchStrategy { get; set; } = BranchAxisStrategy.Parallel;
public List<BranchAxisRequest> BranchAxes { get; set; } = new();
}
/// <summary>
/// 分支轴请求模型
/// </summary>
public class BranchAxisRequest
{
public string BranchAxisName { get; set; }
public int? Priority { get; set; }
public BranchAxisStrategy? NodeStrategy { get; set; }
public List<NodeRequest> Nodes { get; set; } = new();
}
/// <summary>
/// 节点请求模型
/// </summary>
public class NodeRequest
{
public string NodeName { get; set; }
public string NodeType { get; set; }
public int? Priority { get; set; }
public int? Timeout { get; set; }
public int? RetryCount { get; set; }
public bool? AllowSkip { get; set; }
public Dictionary<string, object> BusinessParams { get; set; } = new();
}
#endregion
三、典型应用示例
工单完工处理场景(MES/ERP 核心场景)
/// <summary>
/// 工单完工处理(组轴式执行示例)
/// </summary>
public async Task ProcessWorkOrderCompletion(string workOrderId)
{
// 1. 创建主轴线(工单完工处理)
var masterAxis = new MasterExecutionAxis
{
MasterAxisName = $"工单{workOrderId}完工处理",
BusinessScenario = "工单完工处理",
StructureType = "WorkOrder",
StructureId = workOrderId,
BranchStrategy = BranchAxisStrategy.Priority // 分支轴按优先级执行
};
// 2. 创建分支轴1:基础数据查询(优先级1)
var queryBranchAxis = new BranchExecutionAxis
{
BranchAxisName = "基础数据查询",
MasterAxisId = masterAxis.MasterAxisId,
Priority = 1,
NodeStrategy = BranchAxisStrategy.Parallel // 节点并行执行
};
// 添加查询节点
queryBranchAxis.Nodes.Add(new DataQueryNodeParams
{
NodeName = "查询工单基本信息",
Priority = 1,
Sql = "SELECT * FROM WorkOrder WHERE WorkOrderId = @WorkOrderId",
QueryParams = new Dictionary<string, object> { { "WorkOrderId", workOrderId } }
});
queryBranchAxis.Nodes.Add(new DataQueryNodeParams
{
NodeName = "查询工单生产数据",
Priority = 1,
Sql = "SELECT * FROM ProductionData WHERE WorkOrderId = @WorkOrderId",
QueryParams = new Dictionary<string, object> { { "WorkOrderId", workOrderId } }
});
queryBranchAxis.Nodes.Add(new DataQueryNodeParams
{
NodeName = "查询工单质检数据",
Priority = 2,
Sql = "SELECT * FROM QualityData WHERE WorkOrderId = @WorkOrderId",
QueryParams = new Dictionary<string, object> { { "WorkOrderId", workOrderId } }
});
// 3. 创建分支轴2:数据更新(优先级2)
var updateBranchAxis = new BranchExecutionAxis
{
BranchAxisName = "工单状态更新",
MasterAxisId = masterAxis.MasterAxisId,
Priority = 2,
NodeStrategy = BranchAxisStrategy.Sequential // 节点串行执行
};
updateBranchAxis.Nodes.Add(new DataQueryNodeParams
{
NodeName = "更新工单状态为已完工",
Priority = 1,
Sql = "UPDATE WorkOrder SET Status = 'Completed', CompleteTime = GETDATE() WHERE WorkOrderId = @WorkOrderId",
QueryParams = new Dictionary<string, object> { { "WorkOrderId", workOrderId } },
ReturnData = false
});
updateBranchAxis.Nodes.Add(new DataQueryNodeParams
{
NodeName = "更新生产台账",
Priority = 2,
Sql = "INSERT INTO ProductionLedger (WorkOrderId, CompleteTime, CreateTime) VALUES (@WorkOrderId, GETDATE(), GETDATE())",
QueryParams = new Dictionary<string, object> { { "WorkOrderId", workOrderId } },
ReturnData = false
});
// 4. 创建分支轴3:外部系统推送(优先级3)
var pushBranchAxis = new BranchExecutionAxis
{
BranchAxisName = "外部系统数据推送",
MasterAxisId = masterAxis.MasterAxisId,
Priority = 3,
NodeStrategy = BranchAxisStrategy.Parallel // 节点并行执行
};
pushBranchAxis.Nodes.Add(new ApiCallNodeParams
{
NodeName = "推送完工数据到ERP",
Priority = 1,
ApiUrl = "http://erp-system/api/workorder/complete",
RequestBody = JsonConvert.SerializeObject(new { WorkOrderId = workOrderId }),
AllowSkip = true, // 允许跳过(ERP不可用时不影响主流程)
RetryCount = 3
});
pushBranchAxis.Nodes.Add(new ApiCallNodeParams
{
NodeName = "推送完工数据到WMS",
Priority = 2,
ApiUrl = "http://wms-system/api/inventory/add",
RequestBody = JsonConvert.SerializeObject(new { WorkOrderId = workOrderId }),
AllowSkip = true,
RetryCount = 3
});
// 5. 添加分支轴到主轴线
masterAxis.BranchAxes.Add(queryBranchAxis);
masterAxis.BranchAxes.Add(updateBranchAxis);
masterAxis.BranchAxes.Add(pushBranchAxis);
// 6. 执行主轴线
var engine = AxisGroupExecutorEngine.Instance;
// 设置工单结构的最大并发数
engine.SetStructureMaxConcurrent("WorkOrder", 8);
// 注册事件
engine.MasterAxisCompleted += (masterId, result) =>
{
Console.WriteLine($"工单{workOrderId}完工处理完成,结果:{result}");
};
// 执行
await engine.ExecuteMasterAxisAsync(masterAxis);
// 7. 获取执行结果
Console.WriteLine($"主轴线执行状态:{masterAxis.Status}");
Console.WriteLine($"失败节点数:{masterAxis.FailedNodeCount}");
Console.WriteLine($"跳过节点数:{masterAxis.SkippedNodeCount}");
Console.WriteLine($"组装结果:{masterAxis.AssembledResult}");
}
四、总结
关键点回顾
- 组轴式架构设计:创新性提出 "主执行轴 + 分支执行轴 + 轴节点" 的三层组轴模型,既保证 MES/ERP 业务逻辑的整体关联性,又实现独立功能段落的多线程并行执行,完美适配 "相关但独立" 的业务特征;
- 多结构并发控制:按产线 / 工单 / 工序等结构类型实现分级并发隔离,通过信号量控制不同结构的并发数,避免资源竞争和冲突;
- 原子化节点封装:将复杂琐碎的业务语句封装为标准化轴节点,支持重试、超时、跳过等容错机制,降低代码冗余和出错概率;
- 灵活的执行策略:支持并行、优先级、分批、串行等多种执行策略,可根据业务需求灵活配置;
- 完整的组件化方案:包含可视化 WinForm 界面、高性能组轴执行引擎、标准化 REST API,支持本地操作和外部系统集成;
- 全生命周期管控:提供从轴创建、执行、监控到结果组装的全生命周期管理,支持实时进度追踪、状态监控和结果可视化。
该方案解决了 MES/ERP 场景中多段业务 "相关但独立" 的核心痛点,通过组轴式多线程执行框架将原本串行的繁复业务段落转化为并行执行,显著提升处理效率,同时保证业务逻辑的完整性和数据一致性,可直接落地应用于工单处理、生产数据同步、ERP 接口集成等典型 MES/ERP 业务场景。