添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
529
MX-PD-盘古 - new/PanGu.DieBonderApp/Mw.WorkFlow/WorkflowEngine.cs
Normal file
529
MX-PD-盘古 - new/PanGu.DieBonderApp/Mw.WorkFlow/WorkflowEngine.cs
Normal file
@@ -0,0 +1,529 @@
|
||||
using MW.WorkFlow;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MW.WorkFlow
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 负责执行工作流活动,并支持暂停、恢复、停止、重启和跳转,基于工作流定义和取消功能。
|
||||
/// </summary>
|
||||
public class WorkflowEngine : IDisposable
|
||||
{
|
||||
private const string WorkflowNameContextKey = "WorkflowName";
|
||||
private const string ParentActivityNameContextKey = "ParentActivityName";
|
||||
private const string CurrentStepIdContextKey = "CurrentStepId";
|
||||
private const string NextStepIdContextKey = "NextStepId";
|
||||
private const string WorkflowRuntimeTrackerContextKey = "WorkflowRuntimeTracker";
|
||||
private const string WorkflowFailureMessageContextKey = "WorkflowFailureMessage";
|
||||
private const string WorkflowFailureMessageKeyContextKey = "WorkflowFailureMessageKey";
|
||||
private const string WorkflowFailureMessageArgumentsContextKey = "WorkflowFailureMessageArguments";
|
||||
|
||||
private readonly WorkflowDefinition _workflowDefinition;
|
||||
private readonly WorkflowContext _context;
|
||||
private string _currentStepId;
|
||||
private volatile bool _isPausedRequested; // 外部请求暂停的标志
|
||||
private TaskCompletionSource<bool> _currentPauseSignal; // 当前的暂停信号
|
||||
private CancellationTokenSource _workflowCancellationTokenSource;
|
||||
private Task _workflowExecutionTask;
|
||||
private bool disposedValue;
|
||||
private readonly object _stateLock = new object(); // 用于保护共享状态的锁
|
||||
|
||||
// 当前工作流的状态
|
||||
public WorkflowState CurrentState { get; private set; } = WorkflowState.Created;
|
||||
public bool IsWorkflowPaused => _isPausedRequested;
|
||||
public bool IsWorkflowFinished => _currentStepId == null;
|
||||
public bool IsWorkflowRunning => _workflowExecutionTask != null && !_workflowExecutionTask.IsCompleted;
|
||||
public string CurrentStepId => _currentStepId;
|
||||
public Exception LastException { get; private set; }
|
||||
|
||||
public WorkflowEngine(WorkflowDefinition workflowDefinition, WorkflowContext context)
|
||||
{
|
||||
_workflowDefinition = workflowDefinition ?? throw new ArgumentNullException(nameof(workflowDefinition));
|
||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||
_currentStepId = workflowDefinition.InitialStepId;
|
||||
_isPausedRequested = false;
|
||||
|
||||
_currentPauseSignal = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
_currentPauseSignal.SetResult(true); // 初始时已经完成
|
||||
}
|
||||
|
||||
// 启动工作流的执行,可选参数允许指定起始步骤
|
||||
public void Start(string startStepId = null)
|
||||
{
|
||||
lock (_stateLock)
|
||||
{
|
||||
if (IsWorkflowRunning)
|
||||
{
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流已经在运行中,无法重复启动。");
|
||||
return;
|
||||
}
|
||||
|
||||
// 核心修改逻辑:处理起始步骤
|
||||
if (!string.IsNullOrEmpty(startStepId))
|
||||
{
|
||||
// 验证步骤是否存在
|
||||
if (!_workflowDefinition.ContainsStep(startStepId))
|
||||
{
|
||||
throw new ArgumentException($"指定的起始步骤ID '{startStepId}' 不存在于工作流定义中。", nameof(startStepId));
|
||||
}
|
||||
_currentStepId = startStepId;
|
||||
}
|
||||
else if (_currentStepId == null)
|
||||
{
|
||||
// 如果未指定且当前没有步骤(例如上次运行已结束),重置为初始步骤
|
||||
_currentStepId = _workflowDefinition.InitialStepId;
|
||||
}
|
||||
|
||||
LastException = null;
|
||||
UpdateWorkflowState(WorkflowState.Running);
|
||||
_isPausedRequested = false;
|
||||
_workflowCancellationTokenSource?.Dispose();
|
||||
_workflowCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
// 确保 _currentPauseSignal 处于已完成状态,以便工作流立即开始
|
||||
if (!_currentPauseSignal.Task.IsCompleted)
|
||||
{
|
||||
_currentPauseSignal.TrySetResult(true);
|
||||
}
|
||||
|
||||
// 使用 Task.Run(ExecuteWorkflowInternalAsync) 避免嵌套 Task<Task>
|
||||
_workflowExecutionTask = Task.Run(ExecuteWorkflowInternalAsync);
|
||||
// 注册仅在发生未处理异常时的续体以记录异常,避免未观察异常
|
||||
_workflowExecutionTask.ContinueWith(t =>
|
||||
{
|
||||
Debug.WriteLine($"[WorkflowEngine] 工作流任务发生未处理异常: {t.Exception?.Flatten().InnerException}");
|
||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||
Debug.WriteLine($"[WorkflowEngine] 工作流已启动,从步骤 '{_currentStepId}' 开始。");
|
||||
}
|
||||
}
|
||||
|
||||
// 异步执行工作流中的活动
|
||||
private async Task ExecuteWorkflowInternalAsync()
|
||||
{
|
||||
Debug.WriteLine("\n[WorkflowEngine] 工作流执行开始。");
|
||||
CancellationToken cancellationToken = _workflowCancellationTokenSource.Token;
|
||||
|
||||
|
||||
Func<Task> pauseCheck = async () =>
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (_isPausedRequested)
|
||||
{
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流已暂停,等待恢复...");
|
||||
var pauseTask = _currentPauseSignal.Task;
|
||||
var cancelTask = Task.Delay(Timeout.Infinite, cancellationToken);
|
||||
var finished = await Task.WhenAny(pauseTask, cancelTask).ConfigureAwait(false);
|
||||
if (finished == cancelTask)
|
||||
{
|
||||
// 如果取消任务先完成,则抛出取消
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
// 等待 pauseTask 以传播其可能的异常/取消
|
||||
await pauseTask.ConfigureAwait(false);
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流已恢复。");
|
||||
}
|
||||
};
|
||||
ActivityControl activityControl = new ActivityControl(cancellationToken, pauseCheck);
|
||||
WorkflowStep currentStep = null;
|
||||
try
|
||||
{
|
||||
while (_currentStepId != null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await pauseCheck().ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
currentStep = _workflowDefinition.GetStep(_currentStepId);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
Debug.WriteLine($"[WorkflowEngine] 错误:无法找到步骤ID '{_currentStepId}'。工作流终止。原因: {ex.Message}");
|
||||
HandleWorkflowFault(ex, currentStep);
|
||||
_currentStepId = null;
|
||||
break;
|
||||
}
|
||||
|
||||
IActivity currentActivity = currentStep.Activity;
|
||||
_context.SetData(WorkflowFailureMessageContextKey, string.Empty);
|
||||
_context.SetData<object>(WorkflowFailureMessageKeyContextKey, null);
|
||||
_context.SetData<object[]>(WorkflowFailureMessageArgumentsContextKey, null);
|
||||
UpdateExecutionContext(currentStep);
|
||||
TrackExecutionPointer(currentStep, currentStep.Id);
|
||||
Debug.WriteLine($"\n[WorkflowEngine] 执行步骤: {currentStep.Id}, 活动: {currentActivity.Name}");
|
||||
|
||||
ActivityResult result = ActivityResult.Failure;
|
||||
try
|
||||
{
|
||||
result = await currentActivity.ExecuteAsync(_context, activityControl).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Debug.WriteLine($"[WorkflowEngine] 活动 '{currentActivity.Name}' 被取消。");
|
||||
result = ActivityResult.Canceled;
|
||||
if (CurrentState != WorkflowState.Stopped)
|
||||
{
|
||||
UpdateWorkflowState(WorkflowState.Canceled);
|
||||
}
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[WorkflowEngine] 活动 '{currentActivity.Name}' 执行时发生未处理的异常: {ex.Message}");
|
||||
result = ActivityResult.Failure;
|
||||
HandleWorkflowFault(ex, currentStep);
|
||||
break;
|
||||
}
|
||||
|
||||
Debug.WriteLine($"[WorkflowEngine] 步骤 '{currentStep.Id}' 完成,结果: {result}");
|
||||
|
||||
// 如果状态已变为 Faulted (可能在上面的 catch 中没 break 住,或者其他逻辑导致),双重保险停止
|
||||
if (CurrentState == WorkflowState.Faulted || CurrentState == WorkflowState.Canceled)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == ActivityResult.Failure)
|
||||
{
|
||||
string failureMessage = ResolveWorkflowFailureMessage(currentActivity.Name);
|
||||
Debug.WriteLine($"[WorkflowEngine] {failureMessage}");
|
||||
HandleWorkflowFailure(failureMessage, currentStep);
|
||||
break;
|
||||
}
|
||||
|
||||
string nextStepCandidateId = null;
|
||||
|
||||
foreach (var condition in currentStep.JumpConditions)
|
||||
{
|
||||
if (condition.Condition(_context, result))
|
||||
{
|
||||
nextStepCandidateId = condition.ResolveTargetStepId(_context, result);
|
||||
Debug.WriteLine($"[WorkflowEngine] 条件跳转满足,跳转到步骤 '{nextStepCandidateId}'。");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextStepCandidateId == null && !string.IsNullOrEmpty(currentStep.NextStepId))
|
||||
{
|
||||
nextStepCandidateId = currentStep.NextStepId;
|
||||
Debug.WriteLine($"[WorkflowEngine] 默认跳转,跳转到步骤 '{nextStepCandidateId}'。");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(nextStepCandidateId) && !_workflowDefinition.ContainsStep(nextStepCandidateId))
|
||||
{
|
||||
throw new InvalidOperationException($"步骤 '{currentStep.Id}' 解析出的目标步骤 '{nextStepCandidateId}' 不存在于工作流定义中。");
|
||||
}
|
||||
|
||||
TrackExecutionPointer(currentStep, nextStepCandidateId);
|
||||
|
||||
lock (_stateLock)
|
||||
{
|
||||
if (_currentStepId == currentStep.Id)
|
||||
{
|
||||
_currentStepId = nextStepCandidateId;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine($"[WorkflowEngine] 外部已修改当前步骤,跳过内部跳转逻辑。");
|
||||
}
|
||||
}
|
||||
|
||||
if (_currentStepId == null)
|
||||
{
|
||||
UpdateWorkflowState(WorkflowState.Completed);
|
||||
Debug.WriteLine($"[WorkflowEngine] 工作流已完成。");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流执行被取消。");
|
||||
if (CurrentState != WorkflowState.Stopped)
|
||||
{
|
||||
UpdateWorkflowState(WorkflowState.Canceled);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[WorkflowEngine] 工作流执行过程中发生未处理的异常: {ex.Message}");
|
||||
HandleWorkflowFault(ex, currentStep);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流执行结束。");
|
||||
lock (_stateLock)
|
||||
{
|
||||
_workflowExecutionTask = null;
|
||||
_currentStepId = null;
|
||||
_workflowCancellationTokenSource?.Dispose();
|
||||
_workflowCancellationTokenSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新工作流状态,并记录日志
|
||||
private void UpdateWorkflowState(WorkflowState newState)
|
||||
{
|
||||
if (CurrentState != newState)
|
||||
{
|
||||
CurrentState = newState;
|
||||
Debug.WriteLine($"[WorkflowEngine] 工作流状态已更改: {CurrentState}");
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleWorkflowFault(Exception ex, WorkflowStep currentStep)
|
||||
{
|
||||
LastException = ex;
|
||||
UpdateWorkflowState(WorkflowState.Faulted);
|
||||
|
||||
if (_context.TryGetData<IWorkflowRuntimeTracker>(WorkflowRuntimeTrackerContextKey, out var tracker) && tracker != null)
|
||||
{
|
||||
_context.TryGetData<string>(WorkflowNameContextKey, out var workflowName);
|
||||
_context.TryGetData<string>(ParentActivityNameContextKey, out var flowNameFromContext);
|
||||
_context.TryGetData<string>(CurrentStepIdContextKey, out var currentStepIdFromContext);
|
||||
|
||||
tracker.ReportWorkflowFault(new WorkflowFaultInfo
|
||||
{
|
||||
WorkflowName = workflowName,
|
||||
FlowName = currentStep?.FlowName ?? flowNameFromContext,
|
||||
ActivityName = currentStep?.Activity?.Name,
|
||||
CurrentStepId = currentStep?.Id ?? currentStepIdFromContext ?? _currentStepId,
|
||||
ErrorMessage = ex?.Message,
|
||||
OccurredAt = DateTime.Now
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleWorkflowFailure(string errorMessage, WorkflowStep currentStep)
|
||||
{
|
||||
LastException = new InvalidOperationException(errorMessage);
|
||||
UpdateWorkflowState(WorkflowState.Faulted);
|
||||
|
||||
if (_context.TryGetData<IWorkflowRuntimeTracker>(WorkflowRuntimeTrackerContextKey, out var tracker) && tracker != null)
|
||||
{
|
||||
_context.TryGetData<string>(WorkflowNameContextKey, out var workflowName);
|
||||
_context.TryGetData<string>(ParentActivityNameContextKey, out var flowNameFromContext);
|
||||
_context.TryGetData<string>(CurrentStepIdContextKey, out var currentStepIdFromContext);
|
||||
|
||||
tracker.ReportWorkflowFault(new WorkflowFaultInfo
|
||||
{
|
||||
WorkflowName = workflowName,
|
||||
FlowName = currentStep?.FlowName ?? flowNameFromContext,
|
||||
ActivityName = currentStep?.Activity?.Name,
|
||||
CurrentStepId = currentStep?.Id ?? currentStepIdFromContext ?? _currentStepId,
|
||||
ErrorMessage = errorMessage,
|
||||
OccurredAt = DateTime.Now
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private string ResolveWorkflowFailureMessage(string activityName)
|
||||
{
|
||||
string failureMessage;
|
||||
if (_context.TryGetData<string>(WorkflowFailureMessageContextKey, out failureMessage) &&
|
||||
!string.IsNullOrWhiteSpace(failureMessage))
|
||||
{
|
||||
return failureMessage;
|
||||
}
|
||||
|
||||
return $"活动 '{activityName}' 返回 Failure,工作流按失败结束。";
|
||||
}
|
||||
|
||||
private void UpdateExecutionContext(WorkflowStep currentStep)
|
||||
{
|
||||
_context.SetData(CurrentStepIdContextKey, currentStep.Id);
|
||||
_context.SetData(NextStepIdContextKey, currentStep.Id);
|
||||
_context.SetData(ParentActivityNameContextKey, currentStep.FlowName ?? string.Empty);
|
||||
}
|
||||
|
||||
private void TrackExecutionPointer(WorkflowStep currentStep, string nextStepId)
|
||||
{
|
||||
_context.SetData(NextStepIdContextKey, nextStepId);
|
||||
|
||||
if (_context.TryGetData<IWorkflowRuntimeTracker>(WorkflowRuntimeTrackerContextKey, out var tracker) && tracker != null)
|
||||
{
|
||||
_context.TryGetData<string>(WorkflowNameContextKey, out var workflowName);
|
||||
tracker.UpdateExecutionPointer(new WorkflowExecutionPointer
|
||||
{
|
||||
WorkflowName = workflowName,
|
||||
FlowName = currentStep?.FlowName,
|
||||
ActivityName = currentStep?.Activity?.Name,
|
||||
CurrentStepId = currentStep?.Id,
|
||||
NextStepId = nextStepId,
|
||||
UpdatedAt = DateTime.Now
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 暂停工作流
|
||||
public void Pause()
|
||||
{
|
||||
|
||||
lock (_stateLock)
|
||||
{
|
||||
if (!IsWorkflowRunning)
|
||||
{
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流未运行,无法暂停。");
|
||||
return;
|
||||
}
|
||||
if (_isPausedRequested)
|
||||
{
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流已处于暂停状态。");
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateWorkflowState(WorkflowState.Paused);
|
||||
_isPausedRequested = true;
|
||||
if (_currentPauseSignal.Task.IsCompleted)
|
||||
{
|
||||
_currentPauseSignal = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
}
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流已请求暂停。");
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复工作流
|
||||
public void Resume()
|
||||
{
|
||||
lock (_stateLock)
|
||||
{
|
||||
if (_isPausedRequested)
|
||||
{
|
||||
_currentPauseSignal.TrySetResult(true);
|
||||
_isPausedRequested = false;
|
||||
UpdateWorkflowState(WorkflowState.Running);
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流已恢复。");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流未暂停,无需恢复。");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 停止工作流
|
||||
public async Task StopAsync()
|
||||
{
|
||||
Task taskToAwait = null;
|
||||
lock (_stateLock)
|
||||
{
|
||||
if (!IsWorkflowRunning)
|
||||
{
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流未运行,无法停止。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_workflowCancellationTokenSource?.IsCancellationRequested == true)
|
||||
{
|
||||
taskToAwait = _workflowExecutionTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine("[WorkflowEngine] 已请求停止工作流。");
|
||||
UpdateWorkflowState(WorkflowState.Stopped);
|
||||
_workflowCancellationTokenSource?.Cancel();
|
||||
if (_isPausedRequested)
|
||||
{
|
||||
Resume();
|
||||
}
|
||||
taskToAwait = _workflowExecutionTask;
|
||||
}
|
||||
}
|
||||
|
||||
if (taskToAwait != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await taskToAwait.ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流任务被取消。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[WorkflowEngine] 停止工作流时发生异常: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
lock (_stateLock)
|
||||
{
|
||||
_workflowExecutionTask = null;
|
||||
_currentStepId = null;
|
||||
_workflowCancellationTokenSource?.Dispose();
|
||||
_workflowCancellationTokenSource = null;
|
||||
_isPausedRequested = false;
|
||||
Debug.WriteLine("[WorkflowEngine] 工作流已停止。");
|
||||
}
|
||||
}
|
||||
|
||||
// 重启工作流
|
||||
public async Task RestartAsync(string startFromStepId = null, bool clearContext = true)
|
||||
{
|
||||
await StopAsync().ConfigureAwait(false);
|
||||
lock (_stateLock)
|
||||
{
|
||||
if (clearContext)
|
||||
{
|
||||
_context.Clear();
|
||||
}
|
||||
|
||||
_currentStepId = startFromStepId ?? _workflowDefinition.InitialStepId;
|
||||
}
|
||||
Start();
|
||||
}
|
||||
|
||||
// 跳转到指定步骤
|
||||
public void JumpTo(string stepId)
|
||||
{
|
||||
lock (_stateLock)
|
||||
{
|
||||
if (!_workflowDefinition.GetAllStepIds().Contains(stepId))
|
||||
{
|
||||
throw new ArgumentException($"步骤ID '{stepId}' 不存在。", nameof(stepId));
|
||||
}
|
||||
|
||||
_currentStepId = stepId;
|
||||
var step = _workflowDefinition.GetStep(stepId);
|
||||
UpdateExecutionContext(step);
|
||||
TrackExecutionPointer(step, stepId);
|
||||
Debug.WriteLine($"[WorkflowEngine] 跳转到步骤 '{stepId}'。");
|
||||
|
||||
if (IsWorkflowPaused)
|
||||
{
|
||||
Resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 将异步 Dispose 改为同步;在 .NET Framework 中不要在 Dispose 中使用 async void/Task 未等待
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (IsWorkflowRunning)
|
||||
{
|
||||
// 同步等待 StopAsync 完成以确保资源清理
|
||||
StopAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user