2025-03-20 22:54:10 +08:00
|
|
|
|
using Microsoft.CodeAnalysis;
|
|
|
|
|
|
using Serein.Library;
|
|
|
|
|
|
using Serein.Library.Api;
|
|
|
|
|
|
using Serein.Library.Utils;
|
2025-07-04 11:35:34 +08:00
|
|
|
|
using Serein.NodeFlow.Model;
|
2025-07-29 14:25:31 +08:00
|
|
|
|
using Serein.NodeFlow.Model.Nodes;
|
2025-03-20 22:54:10 +08:00
|
|
|
|
using Serein.NodeFlow.Tool;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Concurrent;
|
2025-07-28 17:38:51 +08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using System.Linq;
|
2025-08-05 11:15:42 +08:00
|
|
|
|
using System.Net.Http.Headers;
|
2025-05-26 23:55:23 +08:00
|
|
|
|
using System.Threading.Tasks.Dataflow;
|
2025-03-20 22:54:10 +08:00
|
|
|
|
using System.Xml.Linq;
|
|
|
|
|
|
|
2025-06-22 21:53:37 +08:00
|
|
|
|
namespace Serein.NodeFlow.Services
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 流程任务管理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class FlowWorkManagement
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 触发器对应的Cts
|
|
|
|
|
|
/// </summary>
|
2025-07-31 23:59:31 +08:00
|
|
|
|
private ConcurrentDictionary<SingleFlipflopNode, CancellationTokenSource> _globalFlipflops = [];
|
2025-03-20 22:54:10 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 结束运行时需要执行的方法
|
|
|
|
|
|
/// </summary>
|
2025-07-31 23:59:31 +08:00
|
|
|
|
private Func<Task>? _exitAction { get; set; }
|
2025-05-26 23:55:23 +08:00
|
|
|
|
|
2025-03-20 22:54:10 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化选项
|
|
|
|
|
|
/// </summary>
|
2025-05-26 23:55:23 +08:00
|
|
|
|
public FlowWorkOptions WorkOptions { get; }
|
2025-03-20 22:54:10 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 流程任务管理
|
|
|
|
|
|
/// </summary>
|
2025-05-26 23:55:23 +08:00
|
|
|
|
/// <param name="options"></param>
|
|
|
|
|
|
public FlowWorkManagement(FlowWorkOptions options)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
2025-05-26 23:55:23 +08:00
|
|
|
|
WorkOptions = options;
|
2025-03-20 22:54:10 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-05-27 18:32:40 +08:00
|
|
|
|
/// 初始化
|
2025-03-20 22:54:10 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public async Task<bool> RunAsync(CancellationToken token)
|
|
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
var sw = Stopwatch.StartNew();
|
|
|
|
|
|
var checkpoints = new Dictionary<string, TimeSpan>();
|
|
|
|
|
|
|
2025-08-05 11:15:42 +08:00
|
|
|
|
|
2025-05-26 23:55:23 +08:00
|
|
|
|
#region 注册所有节点所属的类的类型,如果注册失败则退出
|
2025-05-31 12:15:01 +08:00
|
|
|
|
List<IFlowNode> nodes = new List<IFlowNode>();
|
2025-07-31 23:59:31 +08:00
|
|
|
|
var flowTask = WorkOptions.Flows.Values.ToArray();
|
|
|
|
|
|
foreach (var item in flowTask)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
var temp = item?.GetNodes?.Invoke() ;
|
|
|
|
|
|
if (temp is null)
|
|
|
|
|
|
continue;
|
2025-05-26 23:55:23 +08:00
|
|
|
|
nodes.AddRange(temp);
|
2025-03-20 22:54:10 +08:00
|
|
|
|
}
|
2025-05-26 23:55:23 +08:00
|
|
|
|
if (!RegisterAllType(nodes))
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
|
|
|
|
|
return false;
|
2025-05-26 23:55:23 +08:00
|
|
|
|
}
|
2025-07-31 23:59:31 +08:00
|
|
|
|
checkpoints["注册所有节点类型"] = sw.Elapsed; // 记录注册所有节点类型的时间
|
2025-05-26 23:55:23 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 调用所有流程类的Init、Load事件
|
|
|
|
|
|
|
2025-03-20 22:54:10 +08:00
|
|
|
|
var initState = await TryInit();
|
2025-07-31 23:59:31 +08:00
|
|
|
|
if (!initState)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
return false;
|
2025-07-31 23:59:31 +08:00
|
|
|
|
checkpoints["调用Init事件"] = sw.Elapsed; // 记录调用Init事件的时间
|
2025-03-20 22:54:10 +08:00
|
|
|
|
var loadState = await TryLoadAsync();
|
2025-07-31 23:59:31 +08:00
|
|
|
|
if (!loadState)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
return false;
|
2025-07-31 23:59:31 +08:00
|
|
|
|
checkpoints["调用Load事件"] = sw.Elapsed; // 记录调用Load事件的时间
|
2025-05-26 23:55:23 +08:00
|
|
|
|
#endregion
|
2025-07-31 23:59:31 +08:00
|
|
|
|
var last = TimeSpan.Zero;
|
|
|
|
|
|
foreach (var kv in checkpoints)
|
|
|
|
|
|
{
|
|
|
|
|
|
SereinEnv.WriteLine(InfoType.INFO, $"{kv.Key} 耗时: {(kv.Value - last).TotalMilliseconds} ms");
|
|
|
|
|
|
last = kv.Value;
|
|
|
|
|
|
}
|
2025-05-26 23:55:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 开始调用流程
|
|
|
|
|
|
foreach (var kvp in WorkOptions.Flows)
|
|
|
|
|
|
{
|
|
|
|
|
|
var guid = kvp.Key;
|
|
|
|
|
|
var flow = kvp.Value;
|
2025-07-31 23:59:31 +08:00
|
|
|
|
var flowNodes = flow.GetNodes?.Invoke();
|
|
|
|
|
|
if (flowNodes is null)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
IFlowNode? startNode = flow.GetStartNode?.Invoke();
|
2025-05-26 23:55:23 +08:00
|
|
|
|
// 找到流程的起始节点,开始运行
|
2025-07-31 23:59:31 +08:00
|
|
|
|
if (startNode is null)
|
|
|
|
|
|
continue;
|
2025-05-26 23:55:23 +08:00
|
|
|
|
// 是否后台运行当前画布流程
|
2025-07-31 23:59:31 +08:00
|
|
|
|
if (flow.IsWaitStartFlow)
|
2025-05-26 23:55:23 +08:00
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
_ = Task.Run(async () => await CallNode(startNode), token); // 后台调用流程中的触发器
|
2025-05-26 23:55:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
await CallNode(startNode);
|
2025-05-27 18:32:40 +08:00
|
|
|
|
|
2025-05-26 23:55:23 +08:00
|
|
|
|
}
|
2025-07-31 23:59:31 +08:00
|
|
|
|
await CallFlipflopNode(flow); // 后台调用流程中的触发器
|
2025-05-26 23:55:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 等待流程运行完成
|
2025-03-20 22:54:10 +08:00
|
|
|
|
await CallExit();
|
2025-07-31 23:59:31 +08:00
|
|
|
|
|
2025-03-20 22:54:10 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region 初始化
|
2025-05-26 23:55:23 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化节点所需的所有类型
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
2025-05-31 12:15:01 +08:00
|
|
|
|
private bool RegisterAllType(List<IFlowNode> nodes)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
2025-05-26 23:55:23 +08:00
|
|
|
|
var env = WorkOptions.Environment;
|
2025-07-18 22:45:06 +08:00
|
|
|
|
var ioc = WorkOptions.FlowIOC;
|
|
|
|
|
|
|
2025-08-05 11:15:42 +08:00
|
|
|
|
HashSet<Type> types = new HashSet<Type>();
|
2025-05-26 23:55:23 +08:00
|
|
|
|
var nodeMds = nodes.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息
|
2025-03-20 22:54:10 +08:00
|
|
|
|
var allMds = new List<MethodDetails>();
|
2025-08-05 11:15:42 +08:00
|
|
|
|
IEnumerable<MethodDetails> Where(IEnumerable<MethodDetails> mds)
|
|
|
|
|
|
{
|
|
|
|
|
|
return mds.Where(md => md?.ActingInstanceType is not null && !md.ActingInstanceType.IsSealed && !md.ActingInstanceType.IsAbstract);
|
|
|
|
|
|
}
|
|
|
|
|
|
allMds.AddRange(Where(nodeMds));
|
|
|
|
|
|
allMds.AddRange(Where(WorkOptions.InitMds));
|
|
|
|
|
|
allMds.AddRange(Where(WorkOptions.ExitMds));
|
|
|
|
|
|
allMds.AddRange(Where(WorkOptions.LoadMds));
|
2025-03-20 22:54:10 +08:00
|
|
|
|
var isSuccessful = true;
|
|
|
|
|
|
foreach (var md in allMds)
|
|
|
|
|
|
{
|
2025-08-05 11:15:42 +08:00
|
|
|
|
|
|
|
|
|
|
Type? type = md.ActingInstanceType;
|
|
|
|
|
|
if (type is null)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
2025-08-05 11:15:42 +08:00
|
|
|
|
SereinEnv.WriteLine(InfoType.ERROR, "{md.MethodName} - 没有类型声明");
|
|
|
|
|
|
isSuccessful = false;
|
2025-03-20 22:54:10 +08:00
|
|
|
|
}
|
2025-08-05 11:15:42 +08:00
|
|
|
|
else if (types.Add(type))
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
2025-08-05 11:15:42 +08:00
|
|
|
|
ioc.Register(md.ActingInstanceType);
|
2025-03-20 22:54:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-05 11:15:42 +08:00
|
|
|
|
if(types.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-18 22:45:06 +08:00
|
|
|
|
ioc.Build(); // 绑定初始化时注册的类型
|
2025-03-20 22:54:10 +08:00
|
|
|
|
foreach (var md in allMds)
|
|
|
|
|
|
{
|
2025-07-18 22:45:06 +08:00
|
|
|
|
var instance = ioc.Get(md.ActingInstanceType);
|
2025-03-20 22:54:10 +08:00
|
|
|
|
if (instance is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
SereinEnv.WriteLine(InfoType.ERROR, $"{md.MethodName} - 无法获取类型[{md.ActingInstanceType}]的实例");
|
|
|
|
|
|
isSuccessful = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return isSuccessful;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-31 23:59:31 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 尝试初始化
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="Exception"></exception>
|
2025-03-20 22:54:10 +08:00
|
|
|
|
private async Task<bool> TryInit()
|
|
|
|
|
|
{
|
2025-05-26 23:55:23 +08:00
|
|
|
|
var env = WorkOptions.Environment;
|
|
|
|
|
|
var initMds = WorkOptions.InitMds;
|
|
|
|
|
|
var pool = WorkOptions.FlowContextPool;
|
2025-07-18 22:45:06 +08:00
|
|
|
|
var ioc = WorkOptions.FlowIOC;
|
2025-03-20 22:54:10 +08:00
|
|
|
|
foreach (var md in initMds) // 初始化
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception("不存在对应委托");
|
|
|
|
|
|
}
|
|
|
|
|
|
var context = pool.Allocate();
|
|
|
|
|
|
var instance = ioc.Get(md.ActingInstanceType);
|
|
|
|
|
|
await dd.InvokeAsync(instance, [context]);
|
|
|
|
|
|
pool.Free(context);
|
|
|
|
|
|
}
|
2025-07-18 22:45:06 +08:00
|
|
|
|
ioc.Build(); // 绑定初始化时注册的类型
|
2025-03-20 22:54:10 +08:00
|
|
|
|
var isSuccessful = true;
|
|
|
|
|
|
return isSuccessful;
|
|
|
|
|
|
}
|
2025-07-31 23:59:31 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 尝试加载流程
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="Exception"></exception>
|
2025-03-20 22:54:10 +08:00
|
|
|
|
private async Task<bool> TryLoadAsync()
|
|
|
|
|
|
{
|
2025-05-26 23:55:23 +08:00
|
|
|
|
var env = WorkOptions.Environment;
|
|
|
|
|
|
var loadMds = WorkOptions.LoadMds;
|
|
|
|
|
|
var pool = WorkOptions.FlowContextPool;
|
2025-07-18 22:45:06 +08:00
|
|
|
|
var ioc = WorkOptions.FlowIOC;
|
2025-03-20 22:54:10 +08:00
|
|
|
|
foreach (var md in loadMds) // 加载时
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception("不存在对应委托");
|
|
|
|
|
|
}
|
|
|
|
|
|
var context = pool.Allocate();
|
|
|
|
|
|
var instance = ioc.Get(md.ActingInstanceType);
|
|
|
|
|
|
await dd.InvokeAsync(instance, [context]);
|
|
|
|
|
|
pool.Free(context);
|
|
|
|
|
|
}
|
2025-07-18 22:45:06 +08:00
|
|
|
|
ioc.Build(); // 绑定初始化时注册的类型
|
2025-03-20 22:54:10 +08:00
|
|
|
|
var isSuccessful = true;
|
|
|
|
|
|
return isSuccessful;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2025-07-31 23:59:31 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 结束流程时调用的方法
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="Exception"></exception>
|
2025-03-20 22:54:10 +08:00
|
|
|
|
private async Task<bool> CallExit()
|
|
|
|
|
|
{
|
2025-05-26 23:55:23 +08:00
|
|
|
|
var env = WorkOptions.Environment;
|
|
|
|
|
|
var mds = WorkOptions.ExitMds;
|
|
|
|
|
|
var pool = WorkOptions.FlowContextPool;
|
2025-07-18 22:45:06 +08:00
|
|
|
|
var ioc = WorkOptions.FlowIOC;
|
2025-03-20 22:54:10 +08:00
|
|
|
|
|
|
|
|
|
|
foreach (var md in mds) // 结束时
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception("不存在对应委托");
|
|
|
|
|
|
}
|
|
|
|
|
|
var context = pool.Allocate();
|
|
|
|
|
|
var instance = ioc.Get(md.ActingInstanceType);
|
|
|
|
|
|
await dd.InvokeAsync(instance, [context]);
|
|
|
|
|
|
pool.Free(context);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TerminateAllGlobalFlipflop(); // 确保所有触发器不再运行
|
|
|
|
|
|
SereinEnv.ClearFlowGlobalData(); // 清空全局数据缓存
|
|
|
|
|
|
NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
|
|
|
|
|
|
|
|
|
|
|
|
var isSuccessful = true;
|
|
|
|
|
|
return isSuccessful;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-31 23:59:31 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 调用流程中的触发器节点
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="flow"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-05-27 18:32:40 +08:00
|
|
|
|
private async Task CallFlipflopNode(FlowTask flow)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
2025-05-26 23:55:23 +08:00
|
|
|
|
var env = WorkOptions.Environment;
|
2025-07-31 23:59:31 +08:00
|
|
|
|
var nodes = flow.GetNodes?.Invoke();
|
|
|
|
|
|
if (nodes is null)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
SereinEnv.WriteLine(InfoType.WARN, "流程中没有触发器节点可供执行");
|
|
|
|
|
|
return;
|
2025-03-20 22:54:10 +08:00
|
|
|
|
}
|
2025-07-31 23:59:31 +08:00
|
|
|
|
var flipflopNodes = nodes.Where(item => item is SingleFlipflopNode node
|
|
|
|
|
|
&& node.DebugSetting.IsEnable
|
|
|
|
|
|
&& node.NotExitPreviousNode())
|
|
|
|
|
|
.OfType<SingleFlipflopNode>()
|
|
|
|
|
|
.Select(async node =>
|
|
|
|
|
|
{
|
|
|
|
|
|
await RunGlobalFlipflopAsync(env, node); // 启动流程时启动全局触发器
|
|
|
|
|
|
});
|
|
|
|
|
|
var tasks = flipflopNodes.ToArray();
|
|
|
|
|
|
await Task.WhenAll(tasks);
|
2025-03-20 22:54:10 +08:00
|
|
|
|
}
|
2025-05-26 23:55:23 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-07-31 23:59:31 +08:00
|
|
|
|
/// 从某个节点开始执行
|
2025-05-26 23:55:23 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="startNode"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-07-31 23:59:31 +08:00
|
|
|
|
private async Task CallNode(IFlowNode startNode)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
2025-05-26 23:55:23 +08:00
|
|
|
|
var pool = WorkOptions.FlowContextPool;
|
|
|
|
|
|
var token = WorkOptions.CancellationTokenSource.Token;
|
2025-03-20 22:54:10 +08:00
|
|
|
|
var context = pool.Allocate();
|
|
|
|
|
|
await startNode.StartFlowAsync(context, token);
|
|
|
|
|
|
pool.Free(context);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 从选定的节点开始运行
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="startNode"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-07-07 20:40:24 +08:00
|
|
|
|
public async Task<FlowResult> StartFlowInSelectNodeAsync(IFlowNode startNode)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
2025-07-30 11:29:12 +08:00
|
|
|
|
var pool = WorkOptions.FlowContextPool;
|
|
|
|
|
|
|
2025-07-28 17:38:51 +08:00
|
|
|
|
var sw = Stopwatch.StartNew();
|
|
|
|
|
|
var checkpoints = new Dictionary<string, TimeSpan>();
|
|
|
|
|
|
|
2025-07-30 11:29:12 +08:00
|
|
|
|
|
2025-07-28 17:38:51 +08:00
|
|
|
|
var context = pool.Allocate();
|
|
|
|
|
|
checkpoints["准备Context"] = sw.Elapsed;
|
|
|
|
|
|
|
2025-07-30 11:29:12 +08:00
|
|
|
|
var result = await startNode.StartFlowAsync(context, WorkOptions.CancellationTokenSource.Token); // 开始运行时从选定节点开始运行
|
2025-07-28 17:38:51 +08:00
|
|
|
|
checkpoints["执行流程"] = sw.Elapsed;
|
|
|
|
|
|
|
2025-03-20 22:54:10 +08:00
|
|
|
|
pool.Free(context);
|
2025-07-28 17:38:51 +08:00
|
|
|
|
checkpoints["释放Context"] = sw.Elapsed;
|
|
|
|
|
|
|
|
|
|
|
|
_ = Task.Run(() =>
|
|
|
|
|
|
{
|
2025-07-29 14:25:31 +08:00
|
|
|
|
//var checkpoints = new Dictionary<string, TimeSpan>();
|
2025-07-28 17:38:51 +08:00
|
|
|
|
var last = TimeSpan.Zero;
|
|
|
|
|
|
foreach (var kv in checkpoints)
|
|
|
|
|
|
{
|
|
|
|
|
|
SereinEnv.WriteLine(InfoType.INFO, $"{kv.Key} 耗时: {(kv.Value - last).TotalMilliseconds} ms");
|
|
|
|
|
|
last = kv.Value;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
return result;
|
2025-03-20 22:54:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-07-31 23:59:31 +08:00
|
|
|
|
/// 运行全局触发器
|
2025-03-20 22:54:10 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="singleFlipFlopNode"></param>
|
|
|
|
|
|
/// <param name="env"></param>
|
|
|
|
|
|
public async Task RunGlobalFlipflopAsync(IFlowEnvironment env, SingleFlipflopNode singleFlipFlopNode)
|
|
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
using var cts = new CancellationTokenSource();
|
|
|
|
|
|
if (_globalFlipflops.TryAdd(singleFlipFlopNode, cts))
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
|
|
|
|
|
await FlipflopExecuteAsync(singleFlipFlopNode, cts.Token);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 尝试移除全局触发器
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="singleFlipFlopNode"></param>
|
|
|
|
|
|
public void TerminateGlobalFlipflopRuning(SingleFlipflopNode singleFlipFlopNode)
|
|
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
if (_globalFlipflops.TryRemove(singleFlipFlopNode, out var cts))
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (!cts.IsCancellationRequested)
|
|
|
|
|
|
{
|
|
|
|
|
|
cts.Cancel();
|
|
|
|
|
|
}
|
|
|
|
|
|
cts.Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 终结所有全局触发器
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void TerminateAllGlobalFlipflop()
|
|
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
foreach ((var node, var cts) in _globalFlipflops)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (!cts.IsCancellationRequested)
|
|
|
|
|
|
{
|
|
|
|
|
|
cts.Cancel();
|
|
|
|
|
|
}
|
|
|
|
|
|
cts.Dispose();
|
|
|
|
|
|
}
|
2025-07-31 23:59:31 +08:00
|
|
|
|
_globalFlipflops.Clear();
|
2025-03-20 22:54:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 启动全局触发器
|
|
|
|
|
|
/// </summary>
|
2025-07-31 23:59:31 +08:00
|
|
|
|
/// <param name="flipflopNode">需要全局监听信号的触发器</param>
|
|
|
|
|
|
/// <param name="token">单个触发器持有的</param>
|
2025-03-20 22:54:10 +08:00
|
|
|
|
/// <returns></returns>
|
2025-07-31 23:59:31 +08:00
|
|
|
|
private async Task FlipflopExecuteAsync(SingleFlipflopNode flipflopNode,
|
|
|
|
|
|
CancellationToken token)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
2025-05-26 23:55:23 +08:00
|
|
|
|
var pool = WorkOptions.FlowContextPool;
|
2025-07-31 23:59:31 +08:00
|
|
|
|
while (true)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
if(token.IsCancellationRequested)
|
|
|
|
|
|
{
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
var context = pool.Allocate(); // 从上下文池取出新的实例
|
2025-03-20 22:54:10 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
var result = await flipflopNode.ExecutingAsync(context, token); // 等待触发获取结果
|
|
|
|
|
|
context.AddOrUpdateFlowData(flipflopNode.Guid, result);
|
2025-03-20 22:54:10 +08:00
|
|
|
|
if (context.NextOrientation == ConnectionInvokeType.None)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-07-31 23:59:31 +08:00
|
|
|
|
await CallSuccessorNodesAsync(flipflopNode, token, pool, context);
|
2025-03-20 22:54:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (FlipflopException ex)
|
|
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{flipflopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message);
|
2025-03-20 22:54:10 +08:00
|
|
|
|
if (ex.Type == FlipflopException.CancelClass.CancelFlow)
|
|
|
|
|
|
{
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{flipflopNode.Guid}]异常。"+ ex.Message);
|
2025-03-20 22:54:10 +08:00
|
|
|
|
await Task.Delay(100);
|
|
|
|
|
|
}
|
2025-07-31 23:59:31 +08:00
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
pool.Free(context);
|
|
|
|
|
|
}
|
2025-03-20 22:54:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-21 18:26:01 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 全局触发器触发后的调用
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="singleFlipFlopNode"></param>
|
|
|
|
|
|
/// <param name="singleToken"></param>
|
|
|
|
|
|
/// <param name="pool"></param>
|
|
|
|
|
|
/// <param name="context"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-07-31 23:59:31 +08:00
|
|
|
|
private static async Task CallSuccessorNodesAsync(SingleFlipflopNode singleFlipFlopNode, CancellationToken singleToken, ObjectPool<IFlowContext> pool, IFlowContext context)
|
2025-03-20 22:54:10 +08:00
|
|
|
|
{
|
|
|
|
|
|
var flowState = context.NextOrientation; // 记录一下流程状态
|
|
|
|
|
|
var nextNodes = singleFlipFlopNode.SuccessorNodes[ConnectionInvokeType.Upstream]; // 优先调用上游分支
|
|
|
|
|
|
for (int i = nextNodes.Count - 1; i >= 0 && !singleToken.IsCancellationRequested; i--)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 筛选出启用的节点
|
|
|
|
|
|
if (!nextNodes[i].DebugSetting.IsEnable)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-07-06 14:34:49 +08:00
|
|
|
|
context.SetPreviousNode(nextNodes[i].Guid, singleFlipFlopNode.Guid); // 设置调用关系
|
2025-03-20 22:54:10 +08:00
|
|
|
|
|
|
|
|
|
|
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前检查终端
|
|
|
|
|
|
{
|
|
|
|
|
|
await nextNodes[i].DebugSetting.GetInterruptTask.Invoke();
|
|
|
|
|
|
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
|
|
|
|
|
|
}
|
|
|
|
|
|
await nextNodes[i].StartFlowAsync(context, singleToken); // 启动执行触发器后继分支的节点
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nextNodes = singleFlipFlopNode.SuccessorNodes[flowState]; // 调用对应分支
|
|
|
|
|
|
for (int i = nextNodes.Count - 1; i >= 0 && !singleToken.IsCancellationRequested; i--)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 筛选出启用的节点
|
|
|
|
|
|
if (!nextNodes[i].DebugSetting.IsEnable)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
context.SetPreviousNode(nextNodes[i].Guid, singleFlipFlopNode.Guid);
|
2025-03-20 22:54:10 +08:00
|
|
|
|
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
|
|
|
|
|
|
{
|
|
|
|
|
|
await nextNodes[i].DebugSetting.GetInterruptTask.Invoke();
|
|
|
|
|
|
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
|
|
|
|
|
|
}
|
|
|
|
|
|
await nextNodes[i].StartFlowAsync(context, singleToken); // 启动执行触发器后继分支的节点
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 结束流程
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Exit()
|
|
|
|
|
|
{
|
2025-07-31 23:59:31 +08:00
|
|
|
|
_exitAction?.Invoke();
|
2025-03-20 22:54:10 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|