引言
在现代复杂应用系统中,工作流编排、配置动态管理和异步任务处理往往是核心挑战。OrchestrationFramework 是一个基于 Entity-Component-System(ECS) 架构设计的 C# 框架,它提供了一套完整的工作流生命周期管理、节点与工作流关联、配置自动刷新以及任务并发控制的解决方案。本文将聚焦于框架的工作流相关模块,介绍其核心数据模型、存储管理器、配置自动更新机制以及辅助的任务处理能力,帮助您快速理解如何在项目中应用该框架。
一、核心数据模型
框架定义了简洁而强大的数据模型来抽象工作流及其与节点的关系。
- WorkflowReference
csharp
public class WorkflowReference where TWorkflow : class
{
public string WorkflowId { get; set; }
public TWorkflow Workflow { get; set; }
public HashSet NodeIds { get; set; } = new();
}
WorkflowId:工作流的唯一标识。
Workflow:实际的工作流对象,可以是任何类(如配置对象、流程定义等)。
NodeIds:与该工作流关联的所有节点 ID 集合。节点可以是任何需要与工作流绑定的实体(如 UI 元素、游戏对象、业务步骤等)。
- INodeConfigExtractor
csharp
public interface INodeConfigExtractor where TWorkflow : class
{
string GetWorkflowName(TWorkflow workflow);
IEnumerable GetNodeIds(TWorkflow workflow);
string GetNodeId(TWorkflow workflow, string nodeKey = null);
}
该接口定义了如何从工作流对象中提取节点信息。用户需要根据实际工作流结构实现它,框架依赖此接口来建立工作流与节点的关联。
二、工作流存储管理器
IWorkflowStorageManager 是框架的核心服务接口,定义了工作流存储与查询的操作。
主要功能
注册或更新工作流:string RegisterOrUpdateWorkflow(TWorkflow workflow) 返回工作流 ID。
获取工作流:TWorkflow GetWorkflow(string workflowId)
节点关联查询:
List FindWorkflowsByNode(string nodeId):根据节点 ID 查找所有关联的工作流。
string GetWorkflowIdForNode(string nodeId):获取节点所在的首个工作流 ID(简化版)。
bool IsNodeInAnyWorkflow(string nodeId)
获取所有工作流 ID:List GetAllWorkflowIds()
获取工作流引用:WorkflowReference GetWorkflowReference(string workflowId) 返回包含节点 ID 集合的完整引用。
移除工作流:void RemoveWorkflow(string workflowId)
观察者机制:
void RegisterObserver(string workflowId, Action callback):订阅工作流更新。
void UnregisterObserver(...)
void RegisterRemovalObserver(string workflowId, Action callback):订阅工作流移除事件。
基于ECS的实现:GenericWorkflowStorageManager
框架提供了默认实现 GenericWorkflowStorageManager,它内部利用 ECS 世界来高效管理实体和组件。该实现的主要特点:
后台线程驱动:启动独立线程运行 ECS 更新循环,所有命令通过线程安全的队列提交,保证数据一致性。
读写锁保护:查询操作使用读写锁,支持高并发读取。
工作流-节点映射:通过两个 ECS 实体(工作流实体、节点实体)及组件关系,实现多对多映射,并通过上下文数据维护快速索引。
观察者通知:当工作流组件变化或实体销毁时,触发内部事件,进而调用注册的回调。回调可选择在捕获的同步上下文(如 UI 线程)上执行,便于与界面集成。
使用示例
csharp
// 定义工作流类
public class MyWorkflow { public string Name; public List Steps; }
// 实现节点提取器
public class MyExtractor : INodeConfigExtractor
{
public IEnumerable GetNodeIds(MyWorkflow workflow) => workflow.Steps;
public string GetWorkflowName(MyWorkflow workflow) => workflow.Name;
public string GetNodeId(MyWorkflow workflow, string nodeKey = null) => nodeKey ?? workflow.Steps.FirstOrDefault();
}
// 创建存储管理器
var storage = new GenericWorkflowStorageManager(new MyExtractor());
// 注册工作流
var workflow = new MyWorkflow { Name = "流程A", Steps = new List { "步骤1", "步骤2" } };
string wfId = storage.RegisterOrUpdateWorkflow(workflow);
// 通过节点查询
var wfIds = storage.FindWorkflowsByNode("步骤1");
// 订阅更新
storage.RegisterObserver(wfId, wf => Console.WriteLine($"工作流更新:{wf.Name}"));
// 获取引用
var ref = storage.GetWorkflowReference(wfId);
Console.WriteLine($"工作流 {ref.WorkflowId} 包含节点:{string.Join(",", ref.NodeIds)}");
三、工作流与节点的多对多关系管理
框架通过 ECS 组件实现了工作流与节点的灵活关联:
每个工作流被建模为一个工作流实体,带有 WorkflowComponent(存储工作流 ID、对象、节点 ID 集合)。
每个节点被建模为一个节点实体,带有 NodeComponent(存储节点 ID)和 WorkflowRefComponent(指向所属的工作流实体)。
上下文数据 NodeEntityMapData 维护节点 ID 到节点实体列表的映射,实现快速反向查询。
这种设计支持:
一个工作流可关联多个节点。
一个节点可属于多个工作流(多对多)。
节点实体和工作流实体独立生命周期,移除工作流时自动销毁关联的节点实体。
四、自动刷新的配置基类:GenericWorkflowConfig
在实际应用中,我们经常需要将工作流数据映射到具体的配置对象,并在工作流变化时自动更新配置。GenericWorkflowConfig 抽象类正是为此设计。
工作原理
每个配置实例与一个配置键(通常是节点 ID)绑定。
构造时,自动根据配置键查找对应的工作流 ID,并注册工作流更新观察者。
当工作流发生变化时,OnWorkflowUpdated 被触发,调用 Refresh() 方法重新从工作流中提取数据并更新配置。
子类需实现:
UpdateFromWorkflow(TWorkflow workflow):从工作流更新配置属性。
ResetToDefaults():当工作流不存在或无效时重置为默认值。
IsConfigValidForWorkflow(TWorkflow workflow):验证工作流是否适用于当前配置。
使用示例
csharp
public class MyConfig : GenericWorkflowConfig
{
public string WorkflowName { get; private set; }
public List Steps { get; private set; } = new();
public MyConfig(string configKey, IWorkflowStorageManager<MyWorkflow> storage, string workflowId = null)
: base(configKey, storage, workflowId) { }
protected override void UpdateFromWorkflow(MyWorkflow workflow)
{
WorkflowName = workflow.Name;
Steps = workflow.Steps.ToList();
}
protected override void ResetToDefaults()
{
WorkflowName = "默认";
Steps.Clear();
}
protected override bool IsConfigValidForWorkflow(MyWorkflow workflow) => workflow != null;
}
// 在代码中使用
var config = new MyConfig("步骤1", storage);
// 当工作流更新时,config 自动刷新
五、配置管理器:GenericConfigManager
为了集中管理多个配置实例,框架提供了 GenericConfigManager<TConfig, TWorkflow>。它内部维护一个线程安全的字典缓存,通过工厂方法创建配置实例。
GetOrCreateConfig:根据键获取或创建配置,可传入初始工作流以便首次注册。
TryGetConfig:尝试获取已有配置。
RemoveConfig:移除并释放配置。
ClearAllConfigs:清空所有配置。
该管理器简化了配置的生命周期管理,适用于动态创建和销毁配置的场景。
六、辅助模块:任务处理器与消息队列
虽然这两个模块不直接属于工作流核心,但它们常与工作流结合使用,例如异步处理工作流任务、在工作流之间传递消息等。
- TaskProcessor
通用异步任务处理器,支持按键串行处理任务,防止并发冲突。
SubmitTask:提交任务,同一键的任务会排队执行。
递归深度检测:防止无限递归。
后台处理循环:独立任务不断从阻塞队列中取出任务执行。
适用场景:按用户 ID 串行处理工作流任务、避免资源竞争。
- 消息队列
框架提供 SimpleMessageQueue(FIFO)和 PriorityMessageQueue(优先级队列),均支持:
暂停/恢复
终止当前处理
超时获取
事件通知
在工作流系统中,可用作工作流引擎的事件总线或任务调度队列。
七、总结
OrchestrationFramework 的工作流部分提供了一套完整、高性能且易于扩展的解决方案。其核心优势包括:
解耦与灵活性:通过接口和抽象类,存储管理器、节点提取器均可自定义。
高效查询:ECS 内部实现确保节点与工作流的关联查询快速且内存友好。
自动更新:观察者机制使得配置对象能实时响应工作流变化,无需轮询。
多对多关系:支持节点与工作流的灵活映射,适应复杂业务。
并发安全:读写锁、命令队列、后台线程等设计保证了多线程环境下的稳定性。
无论是构建工作流驱动的配置系统、多租户任务处理平台,还是需要动态响应的业务应用,该框架都能提供坚实的支撑。希望本文能帮助您快速掌握其核心用法,并在实际项目中发挥价值。
csharp
namespace OrchestrationFramework
{
#region 核心数据模型(保持原样)
public class WorkflowReference<TWorkflow> where TWorkflow : class
{
public string WorkflowId { get; set; }
public TWorkflow Workflow { get; set; }
public HashSet<string> NodeIds { get; set; } = new();
}
#endregion
#region 接口定义(保持原样)
public interface IWorkflowStorageManager<TWorkflow> where TWorkflow : class
{
string RegisterOrUpdateWorkflow(TWorkflow workflow);
TWorkflow GetWorkflow(string workflowId);
List<string> FindWorkflowsByNode(string nodeId);
string GetWorkflowIdForNode(string nodeId);
bool IsNodeInAnyWorkflow(string nodeId);
List<string> GetAllWorkflowIds();
WorkflowReference<TWorkflow> GetWorkflowReference(string workflowId);
void RemoveWorkflow(string workflowId);
void RegisterObserver(string workflowId, Action<TWorkflow> callback);
void UnregisterObserver(string workflowId, Action<TWorkflow> callback);
void RegisterRemovalObserver(string workflowId, Action<string> callback);
}
public interface INodeConfigExtractor<TWorkflow> where TWorkflow : class
{
string GetWorkflowName(TWorkflow workflow);
IEnumerable<string> GetNodeIds(TWorkflow workflow);
string GetNodeId(TWorkflow workflow, string nodeKey = null);
}
#endregion
#region ECS 内部组件(适配新框架)
namespace Internal
{
using ContextManagement;
using ECS.Core;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
// 工作流实体组件
internal struct WorkflowComponent<TWorkflow> : IComponent where TWorkflow : class
{
public string WorkflowId;
public TWorkflow Workflow;
public HashSet<string> NodeIds;
}
// 节点实体组件
internal struct NodeComponent : IComponent
{
public string NodeId;
}
// 节点指向所属工作流的引用组件
internal struct WorkflowRefComponent : IComponent
{
public Entity WorkflowEntity;
}
// 上下文数据:节点ID到节点实体列表的映射(支持多对多)
internal class NodeEntityMapData : DirtyContextData
{
// 使用普通 Dictionary 并在读写锁保护下访问
public Dictionary<string, List<Entity>> Map { get; } = new();
}
// 上下文数据:工作流ID到观察者列表
internal class WorkflowObserversData<TWorkflow> : DirtyContextData where TWorkflow : class
{
public ConcurrentDictionary<string, List<Action<TWorkflow>>> Observers { get; } = new();
public ConcurrentDictionary<string, List<Action<string>>> RemovalObservers { get; } = new();
}
// 命令类型
internal enum WorkflowCommandType
{
RegisterOrUpdate,
Remove
}
internal class WorkflowCommand<TWorkflow> where TWorkflow : class
{
public WorkflowCommandType Type { get; set; }
public TWorkflow Workflow { get; set; }
public string WorkflowId { get; set; }
public TaskCompletionSource<string> Tcs { get; set; }
public TaskCompletionSource<bool> RemoveTcs { get; set; }
}
// 工作流注册系统(适配新框架)
internal class WorkflowRegistrationSystem<TWorkflow> : SystemBase where TWorkflow : class
{
private readonly ConcurrentQueue<WorkflowCommand<TWorkflow>> _commandQueue = new();
private NodeEntityMapData _nodeMap;
private WorkflowObserversData<TWorkflow> _observersData;
private readonly INodeConfigExtractor<TWorkflow> _nodeExtractor;
private readonly Func<TWorkflow, string> _workflowIdGenerator;
private readonly ReaderWriterLockSlim _lock;
public WorkflowRegistrationSystem(
INodeConfigExtractor<TWorkflow> nodeExtractor,
Func<TWorkflow, string> workflowIdGenerator,
ReaderWriterLockSlim rwLock)
{
_nodeExtractor = nodeExtractor;
_workflowIdGenerator = workflowIdGenerator;
_lock = rwLock;
}
public override void Initialize(EntityManager entityManager)
{
base.Initialize(entityManager);
var context = entityManager.GetOrCreateContext();
_lock.EnterWriteLock();
try
{
if (!context.TryGetData<NodeEntityMapData>(out _nodeMap))
{
_nodeMap = new NodeEntityMapData();
context.SetData(_nodeMap);
}
if (!context.TryGetData<WorkflowObserversData<TWorkflow>>(out _observersData))
{
_observersData = new WorkflowObserversData<TWorkflow>();
context.SetData(_observersData);
}
}
finally
{
_lock.ExitWriteLock();
}
}
public void SubmitCommand(WorkflowCommand<TWorkflow> command) => _commandQueue.Enqueue(command);
public override void Update(float deltaTime)
{
while (_commandQueue.TryDequeue(out var cmd))
{
_lock.EnterWriteLock();
try
{
switch (cmd.Type)
{
case WorkflowCommandType.RegisterOrUpdate:
ExecuteRegisterOrUpdate(cmd.Workflow, cmd.Tcs);
break;
case WorkflowCommandType.Remove:
ExecuteRemove(cmd.WorkflowId, cmd.RemoveTcs);
break;
}
}
finally
{
_lock.ExitWriteLock();
}
}
}
private void ExecuteRegisterOrUpdate(TWorkflow workflow, TaskCompletionSource<string> tcs)
{
try
{
var workflowId = _workflowIdGenerator(workflow);
var newNodeIds = new HashSet<string>(_nodeExtractor.GetNodeIds(workflow) ?? Enumerable.Empty<string>());
var workflowEntity = FindWorkflowEntity(workflowId);
if (workflowEntity == Entity.Invalid)
{
workflowEntity = EntityManager.CreateEntity();
EntityManager.AddComponent(workflowEntity, new WorkflowComponent<TWorkflow>
{
WorkflowId = workflowId,
Workflow = workflow,
NodeIds = newNodeIds
});
SynchronizeNodeEntities(workflowEntity, null, newNodeIds);
}
else
{
// 获取副本,修改后写回
var wfComp = EntityManager.GetComponent<WorkflowComponent<TWorkflow>>(workflowEntity);
var oldNodeIds = wfComp.NodeIds ?? new HashSet<string>();
wfComp.Workflow = workflow;
wfComp.NodeIds = newNodeIds;
EntityManager.SetComponent(workflowEntity, wfComp);
SynchronizeNodeEntities(workflowEntity, oldNodeIds, newNodeIds);
}
tcs.SetResult(workflowId);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
private void ExecuteRemove(string workflowId, TaskCompletionSource<bool> tcs)
{
try
{
var workflowEntity = FindWorkflowEntity(workflowId);
if (workflowEntity == Entity.Invalid)
{
tcs.SetResult(false);
return;
}
var wfComp = EntityManager.GetComponent<WorkflowComponent<TWorkflow>>(workflowEntity);
var nodeIds = wfComp.NodeIds ?? new HashSet<string>();
foreach (var nodeId in nodeIds)
{
if (_nodeMap.Map.TryGetValue(nodeId, out var nodeEntities))
{
// 找到属于当前工作流的节点实体并移除
var toRemove = nodeEntities.FirstOrDefault(e =>
EntityManager.TryGetComponent<WorkflowRefComponent>(e, out var refComp) &&
refComp.WorkflowEntity == workflowEntity);
if (toRemove != Entity.Invalid)
{
nodeEntities.Remove(toRemove);
EntityManager.DestroyEntity(toRemove);
if (nodeEntities.Count == 0)
_nodeMap.Map.Remove(nodeId);
}
}
}
EntityManager.DestroyEntity(workflowEntity);
tcs.SetResult(true);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
// 同步节点实体:支持多对多
private void SynchronizeNodeEntities(Entity workflowEntity, HashSet<string> oldNodeIds, HashSet<string> newNodeIds)
{
var toRemove = oldNodeIds?.Except(newNodeIds).ToList() ?? new List<string>();
var toAdd = newNodeIds.Except(oldNodeIds ?? Enumerable.Empty<string>()).ToList();
foreach (var nodeId in toRemove)
{
if (_nodeMap.Map.TryGetValue(nodeId, out var nodeEntities))
{
var toDelete = nodeEntities.FirstOrDefault(e =>
EntityManager.TryGetComponent<WorkflowRefComponent>(e, out var refComp) &&
refComp.WorkflowEntity == workflowEntity);
if (toDelete != Entity.Invalid)
{
nodeEntities.Remove(toDelete);
EntityManager.DestroyEntity(toDelete);
if (nodeEntities.Count == 0)
_nodeMap.Map.Remove(nodeId);
}
}
}
foreach (var nodeId in toAdd)
{
var nodeEntity = EntityManager.CreateEntity();
EntityManager.AddComponent(nodeEntity, new NodeComponent { NodeId = nodeId });
EntityManager.AddComponent(nodeEntity, new WorkflowRefComponent { WorkflowEntity = workflowEntity });
if (!_nodeMap.Map.TryGetValue(nodeId, out var nodeEntities))
{
nodeEntities = new List<Entity>();
_nodeMap.Map[nodeId] = nodeEntities;
}
nodeEntities.Add(nodeEntity);
}
}
private Entity FindWorkflowEntity(string workflowId)
{
var query = new EntityQuery(EntityManager).WithComponent<WorkflowComponent<TWorkflow>>();
foreach (var entity in query.Execute())
{
var comp = EntityManager.GetComponent<WorkflowComponent<TWorkflow>>(entity);
if (comp.WorkflowId == workflowId)
return entity;
}
return Entity.Invalid;
}
}
// 工作流通知系统(适配新框架)
internal class WorkflowNotificationSystem<TWorkflow> : SystemBase where TWorkflow : class
{
private WorkflowObserversData<TWorkflow> _observersData;
private readonly HashSet<string> _changedWorkflowIds = new();
private readonly object _lock = new();
private readonly ReaderWriterLockSlim _rwLock;
private readonly SynchronizationContext _syncContext;
private readonly Action _notifyUpdate;
public WorkflowNotificationSystem(
ReaderWriterLockSlim rwLock,
SynchronizationContext syncContext,
Action notifyUpdate)
{
_rwLock = rwLock;
_syncContext = syncContext;
_notifyUpdate = notifyUpdate;
}
public override void Initialize(EntityManager entityManager)
{
base.Initialize(entityManager);
var context = entityManager.GetOrCreateContext();
_rwLock.EnterWriteLock();
try
{
if (!context.TryGetData(out _observersData))
{
_observersData = new WorkflowObserversData<TWorkflow>();
context.SetData(_observersData);
}
}
finally
{
_rwLock.ExitWriteLock();
}
EntityManager.ComponentAdded += OnComponentChanged;
EntityManager.ComponentRemoved += OnComponentChanged;
EntityManager.EntityDestroyed += OnEntityDestroyed;
}
private void OnComponentChanged(Entity entity, Type componentType)
{
if (componentType == typeof(WorkflowComponent<TWorkflow>))
{
// 调用时已在写锁内,无需再次获取锁
if (EntityManager.TryGetComponent<WorkflowComponent<TWorkflow>>(entity, out var wfComp))
{
lock (_lock) _changedWorkflowIds.Add(wfComp.WorkflowId);
_notifyUpdate();
}
}
}
private void OnEntityDestroyed(Entity entity)
{
// 调用时已在写锁内
if (EntityManager.TryGetComponent<WorkflowComponent<TWorkflow>>(entity, out var wfComp))
{
TriggerRemovalCallbacks(wfComp.WorkflowId);
}
}
private void TriggerRemovalCallbacks(string workflowId)
{
if (_observersData.RemovalObservers.TryGetValue(workflowId, out var callbacks))
{
List<Action<string>> snapshot;
lock (callbacks) snapshot = callbacks.ToList(); // 加锁获取快照
foreach (var cb in snapshot)
{
ExecuteCallback(() => cb(workflowId));
}
}
}
public override void Update(float deltaTime)
{
HashSet<string> toNotify;
lock (_lock)
{
toNotify = new HashSet<string>(_changedWorkflowIds);
_changedWorkflowIds.Clear();
}
foreach (var wfId in toNotify)
{
if (_observersData.Observers.TryGetValue(wfId, out var callbacks))
{
TWorkflow workflow = FindWorkflowById(wfId);
if (workflow != null)
{
List<Action<TWorkflow>> snapshot;
lock (callbacks) snapshot = callbacks.ToList(); // 加锁获取快照
foreach (var cb in snapshot)
{
ExecuteCallback(() => cb(workflow));
}
}
}
}
}
private void ExecuteCallback(Action action)
{
if (_syncContext != null)
_syncContext.Post(_ => action(), null);
else
action();
}
private TWorkflow FindWorkflowById(string workflowId)
{
_rwLock.EnterReadLock();
try
{
var query = new EntityQuery(EntityManager).WithComponent<WorkflowComponent<TWorkflow>>();
foreach (var entity in query.Execute())
{
var comp = EntityManager.GetComponent<WorkflowComponent<TWorkflow>>(entity);
if (comp.WorkflowId == workflowId)
return comp.Workflow;
}
return null;
}
finally
{
_rwLock.ExitReadLock();
}
}
public override void Dispose()
{
EntityManager.ComponentAdded -= OnComponentChanged;
EntityManager.ComponentRemoved -= OnComponentChanged;
EntityManager.EntityDestroyed -= OnEntityDestroyed;
base.Dispose();
}
}
}
#endregion
#region 重构后的 GenericWorkflowStorageManager(基于ECS,已适配新框架)
public class GenericWorkflowStorageManager<TWorkflow> : IWorkflowStorageManager<TWorkflow> where TWorkflow : class
{
private readonly Internal.WorkflowRegistrationSystem<TWorkflow> _registrationSystem;
private readonly Internal.WorkflowNotificationSystem<TWorkflow> _notificationSystem;
private readonly EcsWorld _world;
private readonly INodeConfigExtractor<TWorkflow> _nodeExtractor;
private readonly Func<TWorkflow, string> _workflowIdGenerator;
private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private readonly AutoResetEvent _updateEvent = new AutoResetEvent(false);
private readonly Thread _backgroundThread;
private readonly SynchronizationContext _syncContext;
private volatile bool _disposed;
private readonly IContext _context; // 缓存上下文
public GenericWorkflowStorageManager(
INodeConfigExtractor<TWorkflow> nodeExtractor,
Func<TWorkflow, string> workflowIdGenerator = null)
{
_nodeExtractor = nodeExtractor ?? throw new ArgumentNullException(nameof(nodeExtractor));
_workflowIdGenerator = workflowIdGenerator ?? DefaultWorkflowIdGenerator;
_syncContext = SynchronizationContext.Current; // 捕获调用线程的同步上下文(用于回调)
_world = new EcsWorld();
_context = _world.EntityManager.GetOrCreateContext(); // 获取并缓存上下文
_registrationSystem = _world.SystemManager.RegisterSystem(
new Internal.WorkflowRegistrationSystem<TWorkflow>(_nodeExtractor, _workflowIdGenerator, _rwLock));
_notificationSystem = _world.SystemManager.RegisterSystem(
new Internal.WorkflowNotificationSystem<TWorkflow>(_rwLock, _syncContext, () => _updateEvent.Set()));
_backgroundThread = new Thread(RunWorldUpdateLoop) { IsBackground = true };
_backgroundThread.Start();
}
// 默认 ID 生成器:基于工作流类型名称和 GUID,确保唯一性
private static string DefaultWorkflowIdGenerator(TWorkflow workflow)
{
var workflowName = workflow?.GetType().Name ?? "unknown";
using var md5 = System.Security.Cryptography.MD5.Create();
var hashBytes = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes($"workflow_{workflowName}_{Guid.NewGuid()}"));
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
private void RunWorldUpdateLoop()
{
var token = _cts.Token;
var waitHandles = new WaitHandle[] { _updateEvent, token.WaitHandle };
while (!token.IsCancellationRequested)
{
try
{
var index = WaitHandle.WaitAny(waitHandles);
if (index == 1) break; // 取消信号
_world.Update(0); // 执行 ECS 更新
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"World update error: {ex}");
}
}
}
public string RegisterOrUpdateWorkflow(TWorkflow workflow)
{
if (workflow == null) throw new ArgumentNullException(nameof(workflow));
var tcs = new TaskCompletionSource<string>();
var cmd = new Internal.WorkflowCommand<TWorkflow>
{
Type = Internal.WorkflowCommandType.RegisterOrUpdate,
Workflow = workflow,
Tcs = tcs
};
_registrationSystem.SubmitCommand(cmd);
_updateEvent.Set();
return tcs.Task.GetAwaiter().GetResult();
}
public TWorkflow GetWorkflow(string workflowId)
{
ValidateWorkflowId(workflowId);
_rwLock.EnterReadLock();
try
{
var query = new EntityQuery(_world.EntityManager).WithComponent<Internal.WorkflowComponent<TWorkflow>>();
foreach (var entity in query.Execute())
{
var comp = _world.EntityManager.GetComponent<Internal.WorkflowComponent<TWorkflow>>(entity);
if (comp.WorkflowId == workflowId)
return comp.Workflow;
}
return null;
}
finally
{
_rwLock.ExitReadLock();
}
}
public IReadOnlyDictionary<string, WorkflowReference<TWorkflow>> GetReferences()
{
_rwLock.EnterReadLock();
try
{
var dict = new Dictionary<string, WorkflowReference<TWorkflow>>();
var query = new EntityQuery(_world.EntityManager).WithComponent<Internal.WorkflowComponent<TWorkflow>>();
foreach (var entity in query.Execute())
{
var comp = _world.EntityManager.GetComponent<Internal.WorkflowComponent<TWorkflow>>(entity);
var reference = new WorkflowReference<TWorkflow>
{
WorkflowId = comp.WorkflowId,
Workflow = comp.Workflow,
NodeIds = new HashSet<string>(comp.NodeIds ?? new HashSet<string>())
};
dict[comp.WorkflowId] = reference;
}
return dict;
}
finally
{
_rwLock.ExitReadLock();
}
}
public List<string> FindWorkflowsByNode(string nodeId)
{
ValidateNodeId(nodeId);
_rwLock.EnterReadLock();
try
{
var result = new List<string>();
if (_context.TryGetData<Internal.NodeEntityMapData>(out var nodeMap) &&
nodeMap.Map.TryGetValue(nodeId, out var nodeEntities))
{
foreach (var nodeEntity in nodeEntities)
{
if (_world.EntityManager.TryGetComponent<Internal.WorkflowRefComponent>(nodeEntity, out var refComp))
{
var wfEntity = refComp.WorkflowEntity;
if (_world.EntityManager.TryGetComponent<Internal.WorkflowComponent<TWorkflow>>(wfEntity, out var wfComp))
{
result.Add(wfComp.WorkflowId);
}
}
}
}
return result;
}
finally
{
_rwLock.ExitReadLock();
}
}
public string GetWorkflowIdForNode(string nodeId) => FindWorkflowsByNode(nodeId).FirstOrDefault();
public bool IsNodeInAnyWorkflow(string nodeId)
{
if (string.IsNullOrEmpty(nodeId)) return false;
_rwLock.EnterReadLock();
try
{
return _context.TryGetData<Internal.NodeEntityMapData>(out var nodeMap) &&
nodeMap.Map.ContainsKey(nodeId);
}
finally
{
_rwLock.ExitReadLock();
}
}
public List<string> GetAllWorkflowIds()
{
_rwLock.EnterReadLock();
try
{
var query = new EntityQuery(_world.EntityManager).WithComponent<Internal.WorkflowComponent<TWorkflow>>();
return query.Execute()
.Select(e => _world.EntityManager.GetComponent<Internal.WorkflowComponent<TWorkflow>>(e).WorkflowId)
.ToList();
}
finally
{
_rwLock.ExitReadLock();
}
}
public WorkflowReference<TWorkflow> GetWorkflowReference(string workflowId)
{
ValidateWorkflowId(workflowId);
_rwLock.EnterReadLock();
try
{
var workflow = GetWorkflow(workflowId);
if (workflow == null) return null;
var query = new EntityQuery(_world.EntityManager).WithComponent<Internal.WorkflowComponent<TWorkflow>>();
foreach (var entity in query.Execute())
{
var comp = _world.EntityManager.GetComponent<Internal.WorkflowComponent<TWorkflow>>(entity);
if (comp.WorkflowId == workflowId)
{
return new WorkflowReference<TWorkflow>
{
WorkflowId = workflowId,
Workflow = workflow,
NodeIds = new HashSet<string>(comp.NodeIds ?? new HashSet<string>())
};
}
}
return null;
}
finally
{
_rwLock.ExitReadLock();
}
}
public void RemoveWorkflow(string workflowId)
{
ValidateWorkflowId(workflowId);
var tcs = new TaskCompletionSource<bool>();
var cmd = new Internal.WorkflowCommand<TWorkflow>
{
Type = Internal.WorkflowCommandType.Remove,
WorkflowId = workflowId,
RemoveTcs = tcs
};
_registrationSystem.SubmitCommand(cmd);
_updateEvent.Set();
tcs.Task.GetAwaiter().GetResult();
}
public void RegisterObserver(string workflowId, Action<TWorkflow> callback)
{
ValidateRegistrationParameters(workflowId, callback);
_rwLock.EnterWriteLock();
try
{
if (_context.TryGetData<Internal.WorkflowObserversData<TWorkflow>>(out var observersData))
{
var list = observersData.Observers.GetOrAdd(workflowId, _ => new List<Action<TWorkflow>>());
lock (list) if (!list.Contains(callback)) list.Add(callback);
}
}
finally
{
_rwLock.ExitWriteLock();
}
}
public void UnregisterObserver(string workflowId, Action<TWorkflow> callback)
{
ValidateRegistrationParameters(workflowId, callback);
_rwLock.EnterWriteLock();
try
{
if (_context.TryGetData<Internal.WorkflowObserversData<TWorkflow>>(out var observersData) &&
observersData.Observers.TryGetValue(workflowId, out var list))
{
lock (list) list.Remove(callback);
}
}
finally
{
_rwLock.ExitWriteLock();
}
}
public void RegisterRemovalObserver(string workflowId, Action<string> callback)
{
ValidateRegistrationParameters(workflowId, callback);
_rwLock.EnterWriteLock();
try
{
if (_context.TryGetData<Internal.WorkflowObserversData<TWorkflow>>(out var observersData))
{
var list = observersData.RemovalObservers.GetOrAdd(workflowId, _ => new List<Action<string>>());
lock (list) if (!list.Contains(callback)) list.Add(callback);
}
}
finally
{
_rwLock.ExitWriteLock();
}
}
private static void ValidateWorkflowId(string workflowId)
{
if (string.IsNullOrEmpty(workflowId)) throw new ArgumentException("Workflow ID cannot be null or empty", nameof(workflowId));
}
private static void ValidateNodeId(string nodeId)
{
if (string.IsNullOrEmpty(nodeId)) throw new ArgumentException("Node ID cannot be null or empty", nameof(nodeId));
}
private static void ValidateRegistrationParameters<T>(string workflowId, T callback)
{
if (string.IsNullOrEmpty(workflowId)) throw new ArgumentException("Workflow ID cannot be null or empty", nameof(workflowId));
if (callback == null) throw new ArgumentNullException(nameof(callback));
}
public void Dispose()
{
if (_disposed) return;
_disposed = true;
_cts.Cancel();
_updateEvent.Set();
if (_backgroundThread.IsAlive)
_backgroundThread.Join(TimeSpan.FromSeconds(5));
_rwLock.EnterWriteLock();
try
{
_world.Dispose();
}
finally
{
_rwLock.ExitWriteLock();
}
_cts.Dispose();
_updateEvent.Dispose();
_rwLock.Dispose();
}
}
#endregion
#region 重构后的 GenericWorkflowConfig(基于上下文数据自动刷新,保持不变)
public abstract class GenericWorkflowConfig<TWorkflow> : IDisposable where TWorkflow : class
{
private readonly IWorkflowStorageManager<TWorkflow> _storageManager;
private bool _isDisposed;
private Action<TWorkflow> _workflowUpdateCallback;
private string _workflowId;
public string ConfigKey { get; }
public string WorkflowId => _workflowId;
protected GenericWorkflowConfig(string configKey, IWorkflowStorageManager<TWorkflow> storageManager, string workflowId = null)
{
ConfigKey = configKey ?? throw new ArgumentException("ConfigKey cannot be null or empty");
_storageManager = storageManager ?? throw new ArgumentNullException(nameof(storageManager));
Initialize(workflowId);
}
private void Initialize(string workflowId = null)
{
_workflowId = workflowId ?? _storageManager.GetWorkflowIdForNode(ConfigKey);
_workflowUpdateCallback = OnWorkflowUpdated;
if (!string.IsNullOrEmpty(_workflowId))
_storageManager.RegisterObserver(_workflowId, _workflowUpdateCallback);
Refresh();
}
public void Refresh()
{
if (_isDisposed) throw new ObjectDisposedException(GetType().Name);
var workflow = GetWorkflow();
if (workflow != null && IsConfigValidForWorkflow(workflow))
UpdateFromWorkflow(workflow);
else
{
ResetToDefaults();
TryFindNewWorkflow();
}
}
protected TWorkflow GetWorkflow()
{
if (!string.IsNullOrEmpty(_workflowId))
return _storageManager.GetWorkflow(_workflowId);
return TryFindWorkflowForNode();
}
private TWorkflow TryFindWorkflowForNode()
{
var workflowIdForNode = _storageManager.GetWorkflowIdForNode(ConfigKey);
if (!string.IsNullOrEmpty(workflowIdForNode))
{
UpdateWorkflowId(workflowIdForNode);
return _storageManager.GetWorkflow(workflowIdForNode);
}
return null;
}
protected void TryFindNewWorkflow()
{
var newWorkflowId = _storageManager.GetWorkflowIdForNode(ConfigKey);
if (!string.IsNullOrEmpty(newWorkflowId) && newWorkflowId != _workflowId)
UpdateWorkflowId(newWorkflowId);
}
protected void UpdateWorkflowId(string newWorkflowId)
{
if (_isDisposed) throw new ObjectDisposedException(GetType().Name);
if (string.IsNullOrEmpty(newWorkflowId)) throw new ArgumentException("Workflow ID cannot be null or empty");
if (newWorkflowId == _workflowId) return;
if (!string.IsNullOrEmpty(_workflowId))
_storageManager.UnregisterObserver(_workflowId, _workflowUpdateCallback);
_workflowId = newWorkflowId;
_storageManager.RegisterObserver(newWorkflowId, _workflowUpdateCallback);
Refresh();
}
protected virtual void OnWorkflowUpdated(TWorkflow workflow)
{
if (_isDisposed) throw new ObjectDisposedException(GetType().Name);
Refresh();
}
protected abstract void UpdateFromWorkflow(TWorkflow workflow);
protected abstract void ResetToDefaults();
protected abstract bool IsConfigValidForWorkflow(TWorkflow workflow);
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing && !string.IsNullOrEmpty(_workflowId))
_storageManager.UnregisterObserver(_workflowId, _workflowUpdateCallback);
_isDisposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
#endregion
#region 重构后的 GenericConfigManager(使用本地字典,保持不变)
public class GenericConfigManager<TConfig, TWorkflow> : IDisposable
where TConfig : class, IDisposable
where TWorkflow : class
{
private readonly Func<string, IWorkflowStorageManager<TWorkflow>, string, TConfig> _configFactory;
private readonly IWorkflowStorageManager<TWorkflow> _storageManager;
private readonly ConcurrentDictionary<string, TConfig> _cache = new();
private bool _isDisposed;
public IReadOnlyDictionary<string, TConfig> ConfigCache => _cache;
public int Count => _cache.Count;
public GenericConfigManager(
Func<string, IWorkflowStorageManager<TWorkflow>, string, TConfig> configFactory,
IWorkflowStorageManager<TWorkflow> storageManager)
{
_configFactory = configFactory ?? throw new ArgumentNullException(nameof(configFactory));
_storageManager = storageManager ?? throw new ArgumentNullException(nameof(storageManager));
}
public List<TConfig> GetAllConfigs()
{
if (_isDisposed) throw new ObjectDisposedException(nameof(GenericConfigManager<TConfig, TWorkflow>));
return _cache.Values.ToList();
}
public TConfig GetOrCreateConfig(string key, TWorkflow workflow = null)
{
if (_isDisposed) throw new ObjectDisposedException(nameof(GenericConfigManager<TConfig, TWorkflow>));
if (string.IsNullOrEmpty(key)) throw new ArgumentException("Key cannot be null or empty", nameof(key));
return _cache.GetOrAdd(key, k =>
{
string workflowId = null;
if (workflow != null)
workflowId = _storageManager.RegisterOrUpdateWorkflow(workflow);
return _configFactory(k, _storageManager, workflowId);
});
}
public bool TryGetConfig(string key, out TConfig config)
{
config = null;
return !_isDisposed && _cache.TryGetValue(key, out config);
}
public void RemoveConfig(string key)
{
if (_isDisposed) throw new ObjectDisposedException(nameof(GenericConfigManager<TConfig, TWorkflow>));
if (string.IsNullOrEmpty(key)) throw new ArgumentException("Key cannot be null or empty");
if (_cache.TryRemove(key, out var config))
config?.Dispose();
}
public void ClearAllConfigs()
{
if (_isDisposed) throw new ObjectDisposedException(nameof(GenericConfigManager<TConfig, TWorkflow>));
foreach (var key in _cache.Keys.ToArray())
RemoveConfig(key);
}
public void Dispose()
{
if (!_isDisposed)
{
ClearAllConfigs();
_isDisposed = true;
}
}
}
#endregion
#region 任务处理器模块
public class TaskProcessor<T> : IDisposable
{
private readonly BlockingCollection<T> _workQueue = new();
private readonly ConcurrentDictionary<string, bool> _processingKeys = new();
private readonly ConcurrentDictionary<string, int> _recursionDepth = new();
private readonly CancellationTokenSource _cancellationTokenSource = new();
private readonly Func<T, Task> _processItemFunc;
private readonly Func<T, string> _getKeyFunc;
private readonly int _maxRecursionDepth = 10;
private Task _processingTask;
private volatile bool _isDisposed;
private readonly object _lockObject = new();
public TaskProcessor(Func<T, Task> processItemFunc, Func<T, string> getKeyFunc)
{
_processItemFunc = processItemFunc ?? throw new ArgumentNullException(nameof(processItemFunc));
_getKeyFunc = getKeyFunc ?? throw new ArgumentNullException(nameof(getKeyFunc));
}
public void Start()
{
lock (_lockObject)
{
if (_processingTask == null || _processingTask.IsCompleted)
_processingTask = Task.Run(ProcessLoopAsync);
}
}
private async Task ProcessLoopAsync()
{
var token = _cancellationTokenSource.Token;
while (!token.IsCancellationRequested)
{
string key = null;
try
{
T item;
try { item = _workQueue.Take(token); }
catch (OperationCanceledException) { break; }
key = _getKeyFunc(item);
var depth = _recursionDepth.AddOrUpdate(key, 1, (k, v) => v + 1);
if (depth > _maxRecursionDepth)
{
_recursionDepth.TryRemove(key, out _);
throw new InvalidOperationException($"Maximum recursion depth ({_maxRecursionDepth}) exceeded for key: {key}");
}
await ProcessSingleItemAsync(item, token);
}
catch (OperationCanceledException) { break; }
catch (Exception)
{
// 发生异常,延迟后继续循环(深度回退在 finally 中处理)
await Task.Delay(100, token);
}
finally
{
if (key != null)
{
if (_recursionDepth.TryGetValue(key, out var currentDepth))
{
if (currentDepth <= 1)
_recursionDepth.TryRemove(key, out _);
else
_recursionDepth[key] = currentDepth - 1;
}
}
}
}
}
private async Task ProcessSingleItemAsync(T item, CancellationToken token)
{
var key = _getKeyFunc(item);
try
{
_processingKeys[key] = true;
await _processItemFunc(item);
}
finally { _processingKeys.TryRemove(key, out _); }
}
public bool SubmitTask(T item)
{
if (item == null) throw new ArgumentNullException(nameof(item));
if (_isDisposed) throw new ObjectDisposedException(nameof(TaskProcessor<T>));
var key = _getKeyFunc(item);
if (_processingKeys.ContainsKey(key))
{
Task.Delay(50).ContinueWith(_ =>
{
if (!_isDisposed && !_cancellationTokenSource.IsCancellationRequested)
_workQueue.Add(item);
}, _cancellationTokenSource.Token);
return true;
}
_workQueue.Add(item);
return true;
}
public async Task StopAsync(bool graceful = true)
{
_cancellationTokenSource.Cancel();
if (graceful && _processingTask != null)
{
try { await _processingTask; }
catch (OperationCanceledException) { }
catch (Exception) { }
}
while (_workQueue.Count > 0)
_workQueue.TryTake(out _);
}
public void Dispose()
{
if (_isDisposed) return;
_isDisposed = true;
_cancellationTokenSource.Cancel();
try { _processingTask?.Wait(TimeSpan.FromSeconds(5)); }
catch { }
_cancellationTokenSource.Dispose();
_workQueue.Dispose();
}
}
public static class TaskProcessorManager<T>
{
private static readonly ConcurrentDictionary<string, TaskProcessor<T>> _processors = new();
public static TaskProcessor<T> GetOrCreateProcessor(string processorId, Func<T, Task> processItemFunc, Func<T, string> getKeyFunc)
=> _processors.GetOrAdd(processorId, id =>
{
var processor = new TaskProcessor<T>(processItemFunc, getKeyFunc);
processor.Start();
return processor;
});
public static bool TryGetProcessor(string processorId, out TaskProcessor<T> processor)
=> _processors.TryGetValue(processorId, out processor);
public static async Task StopAllProcessorsAsync()
{
var stopTasks = _processors.Values.Select(p => p.StopAsync(true));
await Task.WhenAll(stopTasks);
_processors.Clear();
}
public static void RemoveProcessor(string processorId)
{
if (_processors.TryRemove(processorId, out var processor))
processor.Dispose();
}
}
#endregion
#region 消息队列
public class MessageWrapper<T>
{
public Guid Id { get; set; }
public T Message { get; set; }
public string Name { get; set; }
public int Priority { get; set; }
public DateTime Timestamp { get; set; }
public TimeSpan Age => DateTime.UtcNow - Timestamp;
public override string ToString() => $"消息: {Name}, 优先级: {Priority}, 年龄: {Age.TotalSeconds:F1}秒";
}
public class FunctionTerminationException : Exception
{
public FunctionTerminationException(string message) : base(message) { }
public FunctionTerminationException(string message, Exception innerException) : base(message, innerException) { }
}
public class QueuePausedException : Exception
{
public QueuePausedException(string message) : base(message) { }
public QueuePausedException(string message, Exception innerException) : base(message, innerException) { }
}
public abstract class MessageQueueBase<T> : IDisposable
{
protected readonly CancellationTokenSource _cts = new CancellationTokenSource();
protected readonly object _pauseLock = new object();
protected volatile bool _isStopped, _isPaused, _shouldTerminateCurrent, _disposed;
protected ManualResetEventSlim _pauseEvent = new ManualResetEventSlim(true);
public bool IsStopped => _isStopped;
public bool IsPaused => _isPaused;
public bool ShouldTerminateCurrent => _shouldTerminateCurrent;
public abstract int Count { get; }
public abstract bool IsEmpty { get; }
public virtual Guid StoreMessage(T message, string name = null, int priority = 0)
{
if (_isStopped) throw new InvalidOperationException("队列已停止");
var wrapper = new MessageWrapper<T>
{
Id = Guid.NewGuid(),
Message = message,
Name = name ?? $"消息_{DateTime.UtcNow:yyyyMMddHHmmssfff}",
Priority = priority,
Timestamp = DateTime.UtcNow
};
StoreMessageInternal(wrapper);
return wrapper.Id;
}
public virtual MessageWrapper<T> TryRetrieveMessage()
{
CheckQueueState();
CheckPause();
return TryRetrieveMessageInternal();
}
public virtual MessageWrapper<T> RetrieveMessage(int timeoutMs = -1)
{
CheckQueueState();
return RetrieveMessageInternal(timeoutMs);
}
public virtual void Pause()
{
lock (_pauseLock)
{
if (!_isPaused)
{
_isPaused = true;
_pauseEvent.Reset();
OnPaused?.Invoke(this, EventArgs.Empty);
}
}
}
public virtual void Resume()
{
lock (_pauseLock)
{
if (_isPaused)
{
_isPaused = false;
_pauseEvent.Set();
OnResumed?.Invoke(this, EventArgs.Empty);
}
}
}
public virtual void TerminateCurrent()
{
_shouldTerminateCurrent = true;
SignalForTermination();
OnTerminateRequested?.Invoke(this, EventArgs.Empty);
}
public virtual void ResetTermination() => _shouldTerminateCurrent = false;
public virtual void CheckTermination()
{
if (_shouldTerminateCurrent)
{
_shouldTerminateCurrent = false;
throw new FunctionTerminationException("当前函数执行已被终止");
}
}
public abstract void Clear();
public virtual void Stop()
{
_isStopped = true;
_cts.Cancel();
_pauseEvent.Set();
}
protected void CheckQueueState()
{
if (_isStopped) throw new InvalidOperationException("队列已停止");
}
protected void CheckPause()
{
if (_isPaused) _pauseEvent.Wait();
}
protected CancellationToken GetCombinedCancellationToken()
{
var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(_cts.Token);
if (_isPaused) linkedCts.Cancel();
return linkedCts.Token;
}
protected abstract void StoreMessageInternal(MessageWrapper<T> wrapper);
protected abstract MessageWrapper<T> TryRetrieveMessageInternal();
protected abstract MessageWrapper<T> RetrieveMessageInternal(int timeoutMs);
protected abstract void SignalForTermination();
public event EventHandler OnPaused, OnResumed, OnTerminateRequested;
public virtual void Dispose()
{
if (_disposed) return;
Stop();
_cts.Dispose();
_pauseEvent.Dispose();
_disposed = true;
}
}
public class SimpleMessageQueue<T> : MessageQueueBase<T>
{
private readonly BlockingCollection<MessageWrapper<T>> _queue;
public override int Count => _queue.Count;
public override bool IsEmpty => _queue.Count == 0;
public SimpleMessageQueue(int? capacity = null)
{
var boundedCapacity = capacity ?? int.MaxValue;
_queue = new BlockingCollection<MessageWrapper<T>>(boundedCapacity);
}
protected override void StoreMessageInternal(MessageWrapper<T> wrapper)
{
try { _queue.Add(wrapper, _cts.Token); }
catch (OperationCanceledException) { throw new InvalidOperationException("队列操作被取消"); }
}
protected override MessageWrapper<T> TryRetrieveMessageInternal() => _queue.TryTake(out var message) ? message : null;
protected override MessageWrapper<T> RetrieveMessageInternal(int timeoutMs)
{
try
{
if (timeoutMs >= 0)
return _queue.TryTake(out var message, timeoutMs, GetCombinedCancellationToken()) ? message : null;
else
{
while (!_isStopped)
{
CheckPause();
CheckTermination();
if (_queue.TryTake(out var message, 100, _cts.Token))
return message;
}
throw new OperationCanceledException("队列已停止");
}
}
catch (OperationCanceledException)
{
if (_isPaused) throw new QueuePausedException("队列已暂停");
else throw new InvalidOperationException("队列操作被取消");
}
}
public override void Clear() { while (_queue.TryTake(out _)) { } }
protected override void SignalForTermination() => _pauseEvent.Set();
public override void Stop()
{
base.Stop();
_queue.CompleteAdding();
}
public override void Dispose()
{
if (_disposed) return;
base.Dispose();
_queue.Dispose();
_disposed = true;
}
}
public class PriorityMessageQueue<T> : MessageQueueBase<T>
{
private readonly ConcurrentDictionary<int, ConcurrentQueue<MessageWrapper<T>>> _queues = new();
private readonly AutoResetEvent _signal = new AutoResetEvent(false);
public override int Count => _queues.Sum(q => q.Value.Count);
public override bool IsEmpty => Count == 0;
protected override void StoreMessageInternal(MessageWrapper<T> wrapper)
{
var queue = _queues.GetOrAdd(wrapper.Priority, _ => new ConcurrentQueue<MessageWrapper<T>>());
queue.Enqueue(wrapper);
_signal.Set();
}
protected override MessageWrapper<T> TryRetrieveMessageInternal()
{
var priorities = _queues.Keys.OrderByDescending(p => p).ToList();
foreach (var priority in priorities)
{
if (_queues.TryGetValue(priority, out var queue) && queue.TryDequeue(out var message))
{
if (queue.IsEmpty) _queues.TryRemove(priority, out _);
return message;
}
}
return null;
}
protected override MessageWrapper<T> RetrieveMessageInternal(int timeoutMs)
{
var startTime = DateTime.UtcNow;
while (true)
{
CheckTermination();
var message = TryRetrieveMessageInternal();
if (message != null) return message;
if (timeoutMs >= 0)
{
var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds;
if (elapsed > timeoutMs) return null;
var remaining = (int)(timeoutMs - elapsed);
if (remaining <= 0 || !WaitForSignalOrPause(remaining)) return null;
}
else if (!WaitForSignalOrPause()) return null;
if (_cts.Token.IsCancellationRequested) throw new OperationCanceledException("队列操作被取消");
}
}
public override void Clear() => _queues.Clear();
protected override void SignalForTermination()
{
_pauseEvent.Set();
_signal.Set();
}
private bool WaitForSignalOrPause(int timeoutMs = Timeout.Infinite)
{
var waitHandles = new WaitHandle[] { _signal, _pauseEvent.WaitHandle };
try
{
var result = WaitHandle.WaitAny(waitHandles, timeoutMs);
return result == 0 || result == 1;
}
catch (AbandonedMutexException) { return false; }
}
public override MessageWrapper<T> RetrieveMessage(int timeoutMs = -1)
{
CheckQueueState();
if (_isPaused)
{
if (timeoutMs >= 0) { if (!_pauseEvent.Wait(timeoutMs)) return null; }
else _pauseEvent.Wait();
}
return RetrieveMessageInternal(timeoutMs);
}
public override MessageWrapper<T> TryRetrieveMessage()
{
CheckQueueState();
if (_isPaused) return null;
return TryRetrieveMessageInternal();
}
public override void Stop()
{
base.Stop();
_signal.Set();
}
public override void Dispose()
{
if (_disposed) return;
base.Dispose();
_signal.Dispose();
_disposed = true;
}
}
#endregion
}