530 lines
22 KiB
C#
530 lines
22 KiB
C#
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|