1. 重新设计了 JSON门户类的实现

2. Script脚本添加了原始字符串的实现
3. 修复了Script中无法对  \" 双引号转义的问题
4. 新增了对于集合嵌套取值的支持(目前仅是集合取值)
5. 重新设计了FlowWorkManagement任务启动的逻辑,修复了触发器无法正常运行的问题
6. 在ScriptBaseFunc中新增了 json() 本地函数,支持将字符串转为IJsonToken进行取值。
7. EmitHelper对于集合取值时,反射获取“get_item”委托时存在看你多个MethodInfo,现在可以传入子项类型,帮助匹配目标重载方法
This commit is contained in:
fengjiayi
2025-07-31 23:59:31 +08:00
parent 5f6a58168a
commit 1bccccc835
36 changed files with 948 additions and 335 deletions

View File

@@ -1,9 +1,11 @@
using Serein.Library;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils;
using Serein.NodeFlow.Model;
using Serein.NodeFlow.Model.Nodes;
using Serein.NodeFlow.Services;
using Serein.NodeFlow.Tool;
using System;
using System.Collections;
using System.Collections.Generic;
@@ -52,9 +54,8 @@ namespace Serein.NodeFlow.Env
private ObjectPool<FlowWorkManagement> flowTaskManagementPool;
private FlowWorkOptions flowTaskOptions;
private FlowWorkManagement? flowWorkManagement;
private ISereinIOC? externalIOC;
private Action<ISereinIOC>? setDefultMemberOnReset;
private bool IsUseExternalIOC = false;
@@ -88,9 +89,28 @@ namespace Serein.NodeFlow.Env
}
}
private readonly List<FlowWorkManagement> flowWorkManagements = [];
private FlowWorkManagement GetFWM()
{
var fwm = flowTaskManagementPool.Allocate();
flowWorkManagements.Add(fwm);
return fwm;
}
private void ReturnFWM(FlowWorkManagement fwm)
{
if (flowWorkManagements.Contains(fwm))
{
flowWorkManagements.Remove(fwm);
}
fwm.Exit();
flowTaskManagementPool.Free(fwm);
}
/// <inheritdoc/>
public async Task<bool> StartFlowAsync(string[] canvasGuids)
{
#region
HashSet<string> guids = new HashSet<string>();
bool isBreak = false;
@@ -123,47 +143,49 @@ namespace Serein.NodeFlow.Env
}
#endregion
// 初始化每个画布的数据,转换为流程任务
var flowTasks = guids.Select(guid =>
{
if (!flowModelService.TryGetCanvasModel(guid, out var canvasModel))
{
SereinEnv.WriteLine(InfoType.WARN, $"画布不存在,将不会运行。{guid}");
return default;
}
if (canvasModel.StartNode is null)
{
SereinEnv.WriteLine(InfoType.WARN, $"画布不存在起始节点,将不会运行。{guid}");
return default;
}
return canvasModel;
})
.Where(canvasModel => canvasModel != default && canvasModel.StartNode != null)
.OfType<FlowCanvasDetails>()
.ToDictionary(key => key.Guid,
value => new FlowTask
{
GetStartNode = () => value.StartNode!,
GetNodes = () => flowModelService.GetAllNodeModel(value.Guid),
IsWaitStartFlow = false
});
#region
Dictionary<string, FlowTask> flowTasks = [];
foreach (var guid in guids)
if(flowTasks.Values.Count == 0)
{
if (!flowModelService.TryGetCanvasModel(guid, out var canvasModel))
{
SereinEnv.WriteLine(InfoType.WARN, $"画布不存在,停止运行。{guid}");
return false;
}
var ft = new FlowTask();
ft.GetNodes = () => flowModelService.GetAllNodeModel(guid);
if (canvasModel.StartNode?.Guid is null)
{
SereinEnv.WriteLine(InfoType.WARN, $"画布不存在起始节点,将停止运行。{guid}");
return false;
}
ft.GetStartNode = () => canvasModel.StartNode;
flowTasks.Add(guid, ft);
return false;
}
#endregion
IOC.Reset();
// 初始化IOC
setDefultMemberOnReset?.Invoke(IOC);
IOC.Reset();
IOC.Register<IFlowEnvironment>(() => flowEnvironment);
//externalIOC.Register<IScriptFlowApi, ScriptFlowApi>(); // 注册脚本接口
var flowTaskOptions = new FlowWorkOptions
{
FlowIOC = IOC,
Environment = flowEnvironment, // 流程
Flows = flowTasks,
FlowContextPool = contexts, // 上下文对象池
AutoRegisterTypes = flowLibraryService.GetaAutoRegisterType(), // 需要自动实例化的类型
InitMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Init),
LoadMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Loading),
ExitMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Exit),
};
flowWorkManagement = new FlowWorkManagement(flowTaskOptions);
var cts = new CancellationTokenSource();
var flowWorkManagement = GetFWM();
flowWorkManagement.WorkOptions.Flows = flowTasks;
flowWorkManagement.WorkOptions.AutoRegisterTypes = flowLibraryService.GetaAutoRegisterType(); // 需要自动实例化的类型
flowWorkManagement.WorkOptions.InitMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Init);
flowWorkManagement.WorkOptions.LoadMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Loading);
flowWorkManagement.WorkOptions.ExitMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Exit);
using var cts = new CancellationTokenSource();
try
{
var t = await flowWorkManagement.RunAsync(cts.Token);
@@ -174,22 +196,18 @@ namespace Serein.NodeFlow.Env
}
finally
{
SereinEnv.WriteLine(InfoType.INFO, $"流程运行完毕{Environment.NewLine}"); ;
}
flowTaskOptions = null;
ReturnFWM(flowWorkManagement);
return true;
}
/// <inheritdoc/>
public async Task<TResult> StartFlowAsync<TResult>(string startNodeGuid)
{
var sw = Stopwatch.StartNew();
var checkpoints = new Dictionary<string, TimeSpan>();
var flowTaskManagement = flowTaskManagementPool.Allocate();
var flowWorkManagement = GetFWM();
if (!flowModelService.TryGetNodeModel(startNodeGuid, out IFlowNode? nodeModel))
{
throw new Exception($"节点不存在【{startNodeGuid}】");
@@ -200,10 +218,10 @@ namespace Serein.NodeFlow.Env
}
var flowContextPool = flowTaskManagement.WorkOptions.FlowContextPool;
var flowContextPool = flowWorkManagement.WorkOptions.FlowContextPool;
var context = flowContextPool.Allocate();
checkpoints["准备调用环境"] = sw.Elapsed;
var flowResult = await nodeModel.StartFlowAsync(context, flowTaskManagement.WorkOptions.CancellationTokenSource.Token); // 开始运行时从选定节点开始运行
var flowResult = await nodeModel.StartFlowAsync(context, flowWorkManagement.WorkOptions.CancellationTokenSource.Token); // 开始运行时从选定节点开始运行
checkpoints["调用节点流程"] = sw.Elapsed;
var last = TimeSpan.Zero;
@@ -241,7 +259,7 @@ namespace Serein.NodeFlow.Env
}
context.Reset();
flowContextPool.Free(context);
flowTaskManagementPool.Free(flowTaskManagement);
ReturnFWM(flowWorkManagement); // 释放流程任务管理器
if (flowResult.Value is TResult result)
{
return result;
@@ -256,32 +274,24 @@ namespace Serein.NodeFlow.Env
}
}
/*/// <summary>
/// 单独运行一个节点
/// </summary>
/// <param name="nodeGuid"></param>
/// <returns></returns>
public async Task<object> InvokeNodeAsync(IDynamicContext context, string nodeGuid)
{
object result = Unit.Default;
if (this.NodeModels.TryGetValue(nodeGuid, out var model))
{
CancellationTokenSource cts = new CancellationTokenSource();
result = await model.ExecutingAsync(context, cts.Token);
cts?.Cancel();
}
return result;
}*/
/// <inheritdoc/>
public Task<bool> ExitFlowAsync()
{
flowWorkManagement?.Exit();
foreach(var flowWorkManagement in flowWorkManagements)
{
flowWorkManagement.Exit();
}
UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnFlowRunComplete(new FlowEventArgs()));
IOC.Reset();
flowWorkManagement = null;
GC.Collect();
return Task.FromResult(true);
}
/// <inheritdoc/>
public void ActivateFlipflopNode(string nodeGuid)
{
@@ -313,6 +323,7 @@ namespace Serein.NodeFlow.Env
flowTaskManagement.TerminateGlobalFlipflopRuning(flipflopNode);
}*/
}
/// <inheritdoc/>
public void UseExternalIOC(ISereinIOC ioc, Action<ISereinIOC>? setDefultMemberOnReset = null)
{
@@ -320,11 +331,13 @@ namespace Serein.NodeFlow.Env
this.setDefultMemberOnReset = setDefultMemberOnReset;
IsUseExternalIOC = true;
}
/// <inheritdoc/>
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
{
flowEnvironmentEvent.OnMonitorObjectChanged(new MonitorObjectEventArgs(nodeGuid, monitorData, sourceType));
}
/// <inheritdoc/>
public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type)
{

View File

@@ -242,7 +242,7 @@ namespace Serein.NodeFlow.Env
/// <param name="message">日志内容</param>
/// <param name="type">日志类别</param>
/// <param name="class">日志级别</param>
public void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial)
public void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.General)
{
currentFlowEnvironment.WriteLine(type, message, @class);
}

View File

@@ -127,7 +127,7 @@ namespace Serein.NodeFlow.Env
/// <summary>
/// 信息输出等级
/// </summary>
public InfoClass InfoClass { get; set; } = InfoClass.Trivial;
public InfoClass InfoClass { get; set; } = InfoClass.Debug;
/// <summary>
/// 如果没有全局触发器,且没有循环分支,流程执行完成后自动为 Completion 。
@@ -211,7 +211,7 @@ namespace Serein.NodeFlow.Env
/// <param name="message">日志内容</param>
/// <param name="type">日志类别</param>
/// <param name="class">日志级别</param>
public void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial)
public void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.General)
{
if (@class >= this.InfoClass)
{

View File

@@ -12,7 +12,7 @@ namespace Serein.NodeFlow
/// <summary>
/// 是否异步启动流程
/// </summary>
public bool IsTaskAsync { get; set; }
public bool IsWaitStartFlow { get; set; } = true;
/// <summary>
/// 流程起始节点
@@ -28,7 +28,7 @@ namespace Serein.NodeFlow
/// <summary>
/// 节点任务执行依赖
/// </summary>
public class FlowWorkOptions()
public sealed class FlowWorkOptions()
{
/// <summary>
/// 流程IOC容器

View File

@@ -59,7 +59,7 @@ namespace Serein.NodeFlow.Model.Nodes
if (token.IsCancellationRequested) { return null; }
}
MethodDetails? md = MethodDetails;
MethodDetails md = MethodDetails;
if (md is null)
{
throw new Exception($"节点{Guid}不存在方法信息请检查是否需要重写节点的ExecutingAsync");
@@ -71,7 +71,7 @@ namespace Serein.NodeFlow.Model.Nodes
if (md.IsStatic)
{
object[] args = await this.GetParametersAsync(context, token);
object[] args = md.ParameterDetailss.Length == 0 ? [] : await this.GetParametersAsync(context, token);
var result = await dd.InvokeAsync(null, args);
var flowReslt = FlowResult.OK(this.Guid, context, result);
return flowReslt;

View File

@@ -5,10 +5,22 @@ using System;
namespace Serein.NodeFlow.Model.Nodes
{
[FlowDataProperty(ValuePath = NodeValuePath.Node, IsNodeImp = true)]
public partial class SingleFlipflopNode
{
/// <summary>
/// <para>是否等待后继节点(仅对于全局触发器)</para>
/// <para>如果为 true则在触发器获取结果后等待后继节点执行完成才会调用触发器</para>
/// <para>如果为 false则触发器获取到结果后将使用 _ = Task.Run(...) 再次调用触发器</para>
/// </summary>
private bool _isWaitSuccessorNodes = true;
}
/// <summary>
/// 触发器节点
/// </summary>
public class SingleFlipflopNode : NodeModelBase
public partial class SingleFlipflopNode : NodeModelBase
{
/// <summary>
/// 构造一个新的单触发器节点实例。
@@ -29,46 +41,52 @@ namespace Serein.NodeFlow.Model.Nodes
/// <exception cref="Exception"></exception>
public override async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token)
{
if (token.IsCancellationRequested)
{
return FlowResult.Fail(Guid, context, "流程操作已取消");
}
#region
if (DebugSetting.IsInterrupt) // 执行触发前
{
string guid = Guid.ToString();
SereinEnv.WriteLine(InfoType.INFO, $"[{MethodDetails.MethodName}]进入中断");
await DebugSetting.GetInterruptTask.Invoke();
await Console.Out.WriteLineAsync($"[{MethodDetails.MethodName}]中断已取消,开始执行后继分支");
SereinEnv.WriteLine(InfoType.INFO, $"[{MethodDetails.MethodName}]中断已取消,开始执行后继分支");
}
#endregion
MethodDetails md = MethodDetails;
if (!context.Env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行到某个节点
{
throw new Exception("不存在对应委托");
context.Exit();
context.ExceptionOfRuning = new FlipflopException($"无法获取到委托 {md.MethodName} 的详细信息。请检查流程配置。");
return FlowResult.Fail(Guid, context, "不存在对应委托");
}
var instance = Env.FlowControl.IOC.Get(md.ActingInstanceType);
var ioc = Env.FlowControl.IOC;
var instance = ioc.Get(md.ActingInstanceType);
if (instance is null)
{
Env.FlowControl.IOC.Register(md.ActingInstanceType).Build();
instance = Env.FlowControl.IOC.Get(md.ActingInstanceType);
ioc.Register(md.ActingInstanceType).Build();
instance = ioc.Get(md.ActingInstanceType);
}
await dd.InvokeAsync(instance, [context]);
var args = await this.GetParametersAsync(context, token);
var args = MethodDetails.ParameterDetailss.Length == 0 ? [] : await this.GetParametersAsync(context, token);
// 因为这里会返回不确定的泛型 IFlipflopContext<TRsult>
// 而我们只需要获取到 State 和 Value返回的数据
// 所以使用 dynamic 类型接收
if (token.IsCancellationRequested)
{
return null;
}
dynamic dynamicFlipflopContext = await dd.InvokeAsync(instance, args);
FlipflopStateType flipflopStateType = dynamicFlipflopContext.State;
dynamic flipflopContext = await dd.InvokeAsync(instance, args);
FlipflopStateType flipflopStateType = flipflopContext.State;
context.NextOrientation = flipflopStateType.ToContentType();
if (dynamicFlipflopContext.Type == TriggerDescription.Overtime)
if (flipflopContext.Type == TriggerDescription.Overtime)
{
throw new FlipflopException(MethodDetails.MethodName + "触发器超时触发。Guid" + Guid);
}
object result = dynamicFlipflopContext.Value;
object result = flipflopContext.Value;
var flowReslt = FlowResult.OK(this.Guid, context, result);
return flowReslt;
}

View File

@@ -23,12 +23,12 @@ namespace Serein.NodeFlow.Services
/// <summary>
/// 触发器对应的Cts
/// </summary>
private ConcurrentDictionary<SingleFlipflopNode, CancellationTokenSource> dictGlobalFlipflop = [];
private ConcurrentDictionary<SingleFlipflopNode, CancellationTokenSource> _globalFlipflops = [];
/// <summary>
/// 结束运行时需要执行的方法
/// </summary>
private Func<Task>? ExitAction { get; set; }
private Func<Task>? _exitAction { get; set; }
/// <summary>
/// 初始化选项
@@ -51,60 +51,72 @@ namespace Serein.NodeFlow.Services
/// <returns></returns>
public async Task<bool> RunAsync(CancellationToken token)
{
var sw = Stopwatch.StartNew();
var checkpoints = new Dictionary<string, TimeSpan>();
#region 退
List<IFlowNode> nodes = new List<IFlowNode>();
foreach (var item in WorkOptions.Flows.Values)
var flowTask = WorkOptions.Flows.Values.ToArray();
foreach (var item in flowTask)
{
var temp = item.GetNodes();
var temp = item?.GetNodes?.Invoke() ;
if (temp is null)
continue;
nodes.AddRange(temp);
}
if (!RegisterAllType(nodes))
{
return false;
}
checkpoints["注册所有节点类型"] = sw.Elapsed; // 记录注册所有节点类型的时间
#endregion
#region InitLoad事件
var initState = await TryInit();
if (!initState)
{
if (!initState)
return false;
}
;
checkpoints["调用Init事件"] = sw.Elapsed; // 记录调用Init事件的时间
var loadState = await TryLoadAsync();
if (!loadState)
{
if (!loadState)
return false;
}
;
checkpoints["调用Load事件"] = sw.Elapsed; // 记录调用Load事件的时间
#endregion
var last = TimeSpan.Zero;
foreach (var kv in checkpoints)
{
SereinEnv.WriteLine(InfoType.INFO, $"{kv.Key} 耗时: {(kv.Value - last).TotalMilliseconds} ms");
last = kv.Value;
}
// 开始调用流程
foreach (var kvp in WorkOptions.Flows)
{
var guid = kvp.Key;
var flow = kvp.Value;
var flowNodes = flow.GetNodes();
var flowNodes = flow.GetNodes?.Invoke();
if (flowNodes is null)
continue;
IFlowNode? startNode = flow.GetStartNode?.Invoke();
// 找到流程的起始节点,开始运行
IFlowNode startNode = flow.GetStartNode();
if (startNode is null)
continue;
// 是否后台运行当前画布流程
if (flow.IsTaskAsync)
if (flow.IsWaitStartFlow)
{
_ = Task.Run(async () => await CallStartNode(startNode), token); // 后台调用流程中的触发器
_ = Task.Run(async () => await CallNode(startNode), token); // 后台调用流程中的触发器
}
else
{
await CallStartNode(startNode);
await CallNode(startNode);
}
_ = Task.Run(async () => await CallFlipflopNode(flow), token); // 后台调用流程中的触发器
await CallFlipflopNode(flow); // 后台调用流程中的触发器
}
// 等待流程运行完成
await CallExit();
return true;
}
@@ -153,6 +165,11 @@ namespace Serein.NodeFlow.Services
return isSuccessful;
}
/// <summary>
/// 尝试初始化
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private async Task<bool> TryInit()
{
var env = WorkOptions.Environment;
@@ -175,6 +192,12 @@ namespace Serein.NodeFlow.Services
var isSuccessful = true;
return isSuccessful;
}
/// <summary>
/// 尝试加载流程
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private async Task<bool> TryLoadAsync()
{
var env = WorkOptions.Environment;
@@ -198,6 +221,12 @@ namespace Serein.NodeFlow.Services
return isSuccessful;
}
/// <summary>
/// 结束流程时调用的方法
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private async Task<bool> CallExit()
{
var env = WorkOptions.Environment;
@@ -205,8 +234,6 @@ namespace Serein.NodeFlow.Services
var pool = WorkOptions.FlowContextPool;
var ioc = WorkOptions.FlowIOC;
// var fit = ioc.Get<FlowInterruptTool>();
// fit.CancelAllTrigger(); // 取消所有中断
foreach (var md in mds) // 结束时
{
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
@@ -228,39 +255,44 @@ namespace Serein.NodeFlow.Services
return isSuccessful;
}
/// <summary>
/// 调用流程中的触发器节点
/// </summary>
/// <param name="flow"></param>
/// <returns></returns>
private async Task CallFlipflopNode(FlowTask flow)
{
var env = WorkOptions.Environment;
var flipflopNodes = flow.GetNodes().Where(item => item is SingleFlipflopNode node
var nodes = flow.GetNodes?.Invoke();
if (nodes is null)
{
SereinEnv.WriteLine(InfoType.WARN, "流程中没有触发器节点可供执行");
return;
}
var flipflopNodes = nodes.Where(item => item is SingleFlipflopNode node
&& node.DebugSetting.IsEnable
&& node.NotExitPreviousNode())
.Select(item => (SingleFlipflopNode)item);
//.ToList();// 获取需要再运行开始之前启动的触发器节点
if (flipflopNodes.Count() > 0)
{
var tasks = flipflopNodes.Select(async node =>
{
await RunGlobalFlipflopAsync(env, node); // 启动流程时启动全局触发器
});
await Task.WhenAll(tasks);
}
.OfType<SingleFlipflopNode>()
.Select(async node =>
{
await RunGlobalFlipflopAsync(env, node); // 启动流程时启动全局触发器
});
var tasks = flipflopNodes.ToArray();
await Task.WhenAll(tasks);
}
/// <summary>
/// 从某个节点开始执行
/// 从某个节点开始执行
/// </summary>
/// <param name="startNode"></param>
/// <returns></returns>
private async Task CallStartNode(IFlowNode startNode)
private async Task CallNode(IFlowNode startNode)
{
var pool = WorkOptions.FlowContextPool;
var token = WorkOptions.CancellationTokenSource.Token;
var context = pool.Allocate();
context.Reset();
await startNode.StartFlowAsync(context, token);
context.Exit();
context.Reset();
pool.Free(context);
return;
}
@@ -287,8 +319,6 @@ namespace Serein.NodeFlow.Services
checkpoints["执行流程"] = sw.Elapsed;
context.Reset();
checkpoints["重置流程"] = sw.Elapsed;
pool.Free(context);
checkpoints["释放Context"] = sw.Elapsed;
@@ -307,15 +337,15 @@ namespace Serein.NodeFlow.Services
}
/// <summary>
/// 尝试添加全局触发器
/// 运行全局触发器
/// </summary>
/// <param name="singleFlipFlopNode"></param>
/// <param name="env"></param>
public async Task RunGlobalFlipflopAsync(IFlowEnvironment env, SingleFlipflopNode singleFlipFlopNode)
{
if (dictGlobalFlipflop.TryAdd(singleFlipFlopNode, new CancellationTokenSource()))
using var cts = new CancellationTokenSource();
if (_globalFlipflops.TryAdd(singleFlipFlopNode, cts))
{
var cts = dictGlobalFlipflop[singleFlipFlopNode];
await FlipflopExecuteAsync(singleFlipFlopNode, cts.Token);
}
}
@@ -326,7 +356,7 @@ namespace Serein.NodeFlow.Services
/// <param name="singleFlipFlopNode"></param>
public void TerminateGlobalFlipflopRuning(SingleFlipflopNode singleFlipFlopNode)
{
if (dictGlobalFlipflop.TryRemove(singleFlipFlopNode, out var cts))
if (_globalFlipflops.TryRemove(singleFlipFlopNode, out var cts))
{
if (!cts.IsCancellationRequested)
{
@@ -341,7 +371,7 @@ namespace Serein.NodeFlow.Services
/// </summary>
private void TerminateAllGlobalFlipflop()
{
foreach ((var node, var cts) in dictGlobalFlipflop)
foreach ((var node, var cts) in _globalFlipflops)
{
if (!cts.IsCancellationRequested)
{
@@ -349,37 +379,50 @@ namespace Serein.NodeFlow.Services
}
cts.Dispose();
}
dictGlobalFlipflop.Clear();
_globalFlipflops.Clear();
}
/// <summary>
/// 启动全局触发器
/// </summary>
/// <param name="singleFlipFlopNode">需要全局监听信号的触发器</param>
/// <param name="singleToken">单个触发器持有的</param>
/// <param name="flipflopNode">需要全局监听信号的触发器</param>
/// <param name="token">单个触发器持有的</param>
/// <returns></returns>
private async Task FlipflopExecuteAsync(SingleFlipflopNode singleFlipFlopNode,
CancellationToken singleToken)
private async Task FlipflopExecuteAsync(SingleFlipflopNode flipflopNode,
CancellationToken token)
{
var pool = WorkOptions.FlowContextPool;
while (!singleToken.IsCancellationRequested && !singleToken.IsCancellationRequested)
while (true)
{
if(token.IsCancellationRequested)
{
break;
}
var context = pool.Allocate(); // 从上下文池取出新的实例
try
{
var context = pool.Allocate(); // 启动全局触发器时新建上下文
var newFlowData = await singleFlipFlopNode.ExecutingAsync(context, singleToken); // 获取触发器等待Task
context.AddOrUpdateFlowData(singleFlipFlopNode.Guid, newFlowData);
var result = await flipflopNode.ExecutingAsync(context, token); // 等待触发获取结果
context.AddOrUpdateFlowData(flipflopNode.Guid, result);
if (context.NextOrientation == ConnectionInvokeType.None)
{
continue;
}
_ = Task.Run(() => CallSubsequentNode(singleFlipFlopNode, singleToken, pool, context)); // 重新启动触发器
await CallSuccessorNodesAsync(flipflopNode, token, pool, context);
/*if (flipflopNode.IsWaitSuccessorNodes)
{
_ = Task.Run(async () => await CallSuccessorNodesAsync(flipflopNode, token, pool, context));
}
else
{
await CallSuccessorNodesAsync(flipflopNode, token, pool, context);
}*/
}
catch (FlipflopException ex)
{
SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{singleFlipFlopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message);
SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{flipflopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message);
if (ex.Type == FlipflopException.CancelClass.CancelFlow)
{
break;
@@ -387,9 +430,15 @@ namespace Serein.NodeFlow.Services
}
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{singleFlipFlopNode.Guid}]异常。"+ ex.Message);
SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{flipflopNode.Guid}]异常。"+ ex.Message);
await Task.Delay(100);
}
finally
{
context.Reset();
pool.Free(context);
}
}
}
@@ -402,7 +451,7 @@ namespace Serein.NodeFlow.Services
/// <param name="pool"></param>
/// <param name="context"></param>
/// <returns></returns>
private static async Task? CallSubsequentNode(SingleFlipflopNode singleFlipFlopNode, CancellationToken singleToken, ObjectPool<IFlowContext> pool, IFlowContext context)
private static async Task CallSuccessorNodesAsync(SingleFlipflopNode singleFlipFlopNode, CancellationToken singleToken, ObjectPool<IFlowContext> pool, IFlowContext context)
{
var flowState = context.NextOrientation; // 记录一下流程状态
var nextNodes = singleFlipFlopNode.SuccessorNodes[ConnectionInvokeType.Upstream]; // 优先调用上游分支
@@ -441,8 +490,6 @@ namespace Serein.NodeFlow.Services
await nextNodes[i].StartFlowAsync(context, singleToken); // 启动执行触发器后继分支的节点
}
context.Reset();
pool.Free(context);
}
/// <summary>
@@ -450,7 +497,7 @@ namespace Serein.NodeFlow.Services
/// </summary>
public void Exit()
{
ExitAction?.Invoke();
_exitAction?.Invoke();
}