333 lines
14 KiB
C#
333 lines
14 KiB
C#
|
|
using MainShell.Alarm;
|
|||
|
|
using MainShell.Common;
|
|||
|
|
using MainShell.Log;
|
|||
|
|
using MainShell.Vision;
|
|||
|
|
using MW.WorkFlow;
|
|||
|
|
using Stylet;
|
|||
|
|
using System;
|
|||
|
|
using System.Threading;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
|
|||
|
|
namespace MainShell.Process
|
|||
|
|
{
|
|||
|
|
public class ChipPreparationRequestHandler : IHandle<ChipPreparationRequestedEventArgs>, IHandle<ChipPreparationStateChangedEventArgs>, IDisposable
|
|||
|
|
{
|
|||
|
|
private readonly IEventAggregator _eventAggregator;
|
|||
|
|
private readonly PreparationAreaService _preparationAreaService;
|
|||
|
|
private readonly AlarmOperate _alarmOperate;
|
|||
|
|
private readonly WorkflowRunner _workflowRunner;
|
|||
|
|
private readonly SemaphoreSlim _serialGate = new SemaphoreSlim(1, 1);
|
|||
|
|
private readonly SemaphoreSlim _runnerStateGate = new SemaphoreSlim(1, 1);
|
|||
|
|
private readonly CancellationTokenSource _disposeCts = new CancellationTokenSource();
|
|||
|
|
private bool _disposed;
|
|||
|
|
|
|||
|
|
public ChipPreparationRequestHandler(IEventAggregator eventAggregator, PreparationAreaService preparationAreaService, AlarmOperate alarmOperate)
|
|||
|
|
{
|
|||
|
|
_eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
|
|||
|
|
_preparationAreaService = preparationAreaService ?? throw new ArgumentNullException(nameof(preparationAreaService));
|
|||
|
|
_alarmOperate = alarmOperate ?? throw new ArgumentNullException(nameof(alarmOperate));
|
|||
|
|
_workflowRunner = new WorkflowRunner();
|
|||
|
|
|
|||
|
|
_eventAggregator.Subscribe(this);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void Handle(ChipPreparationRequestedEventArgs message)
|
|||
|
|
{
|
|||
|
|
if (message == null || message.Request == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ChipPreparationRequest request = CloneRequest(message.Request);
|
|||
|
|
_ = ProcessRequestAsync(request);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void Handle(ChipPreparationStateChangedEventArgs message)
|
|||
|
|
{
|
|||
|
|
if (message == null || message.Snapshot == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ChipPreparationStateSnapshot snapshot = CloneSnapshot(message.Snapshot);
|
|||
|
|
_ = SynchronizeRunnerStateAsync(snapshot);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void Dispose()
|
|||
|
|
{
|
|||
|
|
if (_disposed)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_disposed = true;
|
|||
|
|
_disposeCts.Cancel();
|
|||
|
|
_eventAggregator.Unsubscribe(this);
|
|||
|
|
_workflowRunner.Dispose();
|
|||
|
|
_disposeCts.Dispose();
|
|||
|
|
_serialGate.Dispose();
|
|||
|
|
_runnerStateGate.Dispose();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private async Task ProcessRequestAsync(ChipPreparationRequest request)
|
|||
|
|
{
|
|||
|
|
bool gateEntered = false;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
await _serialGate.WaitAsync(_disposeCts.Token);
|
|||
|
|
gateEntered = true;
|
|||
|
|
|
|||
|
|
string.Format("Chip preparation request started. {0}.", BuildRequestSummary(request)).LogProcessInfo();
|
|||
|
|
|
|||
|
|
ChipPreparationWaitResult executeResult = await ExecuteOnDemandActivityAsync(request);
|
|||
|
|
string rejectReason;
|
|||
|
|
|
|||
|
|
if (executeResult.Success)
|
|||
|
|
{
|
|||
|
|
_preparationAreaService.TryMarkReady(request.RequestId, out rejectReason);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
string errorMessage = string.IsNullOrWhiteSpace(executeResult.ErrorMessage) ? "оƬ<C6AC><D7BC>ִ<EFBFBD><D6B4>ʧ<EFBFBD>ܡ<EFBFBD>" : executeResult.ErrorMessage;
|
|||
|
|
_preparationAreaService.TryMarkFault(errorMessage, out rejectReason);
|
|||
|
|
int? visionAlarmId = ResolveVisionAlarmId(executeResult);
|
|||
|
|
if (visionAlarmId.HasValue)
|
|||
|
|
{
|
|||
|
|
await _alarmOperate.AlertAsync(
|
|||
|
|
visionAlarmId.Value,
|
|||
|
|
nameof(ChipPreparationRequestHandler),
|
|||
|
|
"Vision alarm triggered",
|
|||
|
|
BuildAlarmTriggerSummary(request, executeResult)).ConfigureAwait(false);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (OperationCanceledException)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
string.Format("Chip preparation request failed with exception. {0}. {1}", BuildRequestSummary(request), ex).LogProcessError();
|
|||
|
|
string rejectReason;
|
|||
|
|
_preparationAreaService.TryMarkFault("оƬ<C6AC><D7BC>ִ<EFBFBD><D6B4><EFBFBD>쳣: " + ex.Message, out rejectReason);
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
if (gateEntered)
|
|||
|
|
{
|
|||
|
|
_serialGate.Release();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private async Task<ChipPreparationWaitResult> ExecuteOnDemandActivityAsync(ChipPreparationRequest request)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
WorkflowContext context = new WorkflowContext();
|
|||
|
|
context[WorkflowContextKeys.WorkflowName] = ProcessFlowName.ChipPreparationOnDemandFlow;
|
|||
|
|
|
|||
|
|
string activityName = request != null && request.Action == ChipPreparationAction.Unload
|
|||
|
|
? ProcessFlowName.ChipUnloadExecuteActivity
|
|||
|
|
: ProcessFlowName.ChipLoadExecuteActivity;
|
|||
|
|
ChipPreparationExecuteActivity activity = new ChipPreparationExecuteActivity(activityName, request);
|
|||
|
|
|
|||
|
|
WorkflowRunCompletedEventArgs runResult = await _workflowRunner.RunActivityWithResultAsync(activity, context);
|
|||
|
|
if (runResult == null)
|
|||
|
|
{
|
|||
|
|
string.Format("Chip preparation request returned no workflow result. {0}.", BuildRequestSummary(request)).LogProcessError();
|
|||
|
|
return ChipPreparationWaitResult.CreateFailure("оƬ<C6AC><D7BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD><EFBFBD>ִ<EFBFBD>н<EFBFBD><D0BD><EFBFBD><EFBFBD><EFBFBD>");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
switch (runResult.FinalState)
|
|||
|
|
{
|
|||
|
|
case WorkflowState.Completed:
|
|||
|
|
string.Format("Chip preparation request completed. {0}, FinalState={1}.", BuildRequestSummary(request), runResult.FinalState).LogProcessInfo();
|
|||
|
|
return ChipPreparationWaitResult.CreateSuccess();
|
|||
|
|
case WorkflowState.Canceled:
|
|||
|
|
string.Format("Chip preparation request canceled. {0}, FinalState={1}, ErrorMessage={2}.", BuildRequestSummary(request), runResult.FinalState, NormalizeLogValue(runResult.Error)).LogProcessError();
|
|||
|
|
return ChipPreparationWaitResult.CreateCanceled("оƬ<C6AC><D7BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>");
|
|||
|
|
case WorkflowState.Faulted:
|
|||
|
|
string.Format("Chip preparation request faulted. {0}, FinalState={1}, ErrorMessage={2}.", BuildRequestSummary(request), runResult.FinalState, NormalizeLogValue(runResult.Error)).LogProcessError();
|
|||
|
|
return ChipPreparationWaitResult.CreateFailure(string.IsNullOrWhiteSpace(runResult.Error)
|
|||
|
|
? "оƬ<C6AC><D7BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4>ʧ<EFBFBD>ܡ<EFBFBD>"
|
|||
|
|
: runResult.Error);
|
|||
|
|
default:
|
|||
|
|
string.Format("Chip preparation request returned unexpected state. {0}, FinalState={1}, ErrorMessage={2}.", BuildRequestSummary(request), runResult.FinalState, NormalizeLogValue(runResult.Error)).LogProcessError();
|
|||
|
|
return ChipPreparationWaitResult.CreateFailure(string.Format("оƬ<C6AC><D7BC><EFBFBD><EFBFBD><EFBFBD>̷<EFBFBD><CCB7><EFBFBD><EFBFBD><EFBFBD>δԤ<CEB4><D4A4>״̬: {0}<7D><>", runResult.FinalState));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
string.Format("Chip preparation workflow execution threw an exception. {0}. {1}", BuildRequestSummary(request), ex).LogProcessError();
|
|||
|
|
return ChipPreparationWaitResult.CreateFailure(ex.Message);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private async Task SynchronizeRunnerStateAsync(ChipPreparationStateSnapshot snapshot)
|
|||
|
|
{
|
|||
|
|
if (snapshot == null || _disposed)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
await _runnerStateGate.WaitAsync(_disposeCts.Token).ConfigureAwait(false);
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (snapshot.Status == ChipPreparationStatus.Paused)
|
|||
|
|
{
|
|||
|
|
string.Format("Chip preparation runner paused. {0}.", BuildSnapshotSummary(snapshot)).LogProcessDebug();
|
|||
|
|
_workflowRunner.Pause();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (snapshot.Status == ChipPreparationStatus.Preparing ||
|
|||
|
|
snapshot.Status == ChipPreparationStatus.Loading ||
|
|||
|
|
snapshot.Status == ChipPreparationStatus.Unloading)
|
|||
|
|
{
|
|||
|
|
string.Format("Chip preparation runner resumed. {0}.", BuildSnapshotSummary(snapshot)).LogProcessDebug();
|
|||
|
|
_workflowRunner.Resume();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ((snapshot.Status == ChipPreparationStatus.Idle || snapshot.Status == ChipPreparationStatus.Faulted) &&
|
|||
|
|
_workflowRunner.IsRunning)
|
|||
|
|
{
|
|||
|
|
string.Format("Chip preparation runner stopping. {0}.", BuildSnapshotSummary(snapshot)).LogProcessDebug();
|
|||
|
|
await _workflowRunner.StopAsync().ConfigureAwait(false);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (OperationCanceledException)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
_runnerStateGate.Release();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static ChipPreparationRequest CloneRequest(ChipPreparationRequest request)
|
|||
|
|
{
|
|||
|
|
if (request == null)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return new ChipPreparationRequest
|
|||
|
|
{
|
|||
|
|
RequestId = request.RequestId,
|
|||
|
|
RecipeName = request.RecipeName,
|
|||
|
|
Action = request.Action,
|
|||
|
|
SourceStepId = request.SourceStepId
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static ChipPreparationStateSnapshot CloneSnapshot(ChipPreparationStateSnapshot snapshot)
|
|||
|
|
{
|
|||
|
|
if (snapshot == null)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return new ChipPreparationStateSnapshot
|
|||
|
|
{
|
|||
|
|
Status = snapshot.Status,
|
|||
|
|
ActiveRequestId = snapshot.ActiveRequestId,
|
|||
|
|
RecipeName = snapshot.RecipeName,
|
|||
|
|
SourceStepId = snapshot.SourceStepId,
|
|||
|
|
CurrentStage = snapshot.CurrentStage,
|
|||
|
|
ErrorMessage = snapshot.ErrorMessage,
|
|||
|
|
LastUpdatedTime = snapshot.LastUpdatedTime,
|
|||
|
|
CurrentAction = snapshot.CurrentAction,
|
|||
|
|
IsChipLoaded = snapshot.IsChipLoaded
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
private static int? ResolveVisionAlarmId(ChipPreparationWaitResult executeResult)
|
|||
|
|
{
|
|||
|
|
if (executeResult == null)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!string.IsNullOrWhiteSpace(executeResult.ErrorMessage) &&
|
|||
|
|
executeResult.ErrorMessage.IndexOf("Vision", StringComparison.OrdinalIgnoreCase) >= 0)
|
|||
|
|
{
|
|||
|
|
return VisionAlarmIds.TemplateMatchFailed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string BuildRequestSummary(ChipPreparationRequest request)
|
|||
|
|
{
|
|||
|
|
if (request == null)
|
|||
|
|
{
|
|||
|
|
return "RequestId=N/A, Action=None, RecipeName=N/A, SourceStepId=N/A";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return string.Format(
|
|||
|
|
"RequestId={0}, Action={1}, RecipeName={2}, SourceStepId={3}",
|
|||
|
|
NormalizeLogValue(request.RequestId),
|
|||
|
|
request.Action,
|
|||
|
|
NormalizeLogValue(request.RecipeName),
|
|||
|
|
NormalizeLogValue(request.SourceStepId));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string BuildSnapshotSummary(ChipPreparationStateSnapshot snapshot)
|
|||
|
|
{
|
|||
|
|
if (snapshot == null)
|
|||
|
|
{
|
|||
|
|
return "Status=N/A, ActiveRequestId=N/A, CurrentAction=None, SourceStepId=N/A, IsChipLoaded=False";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return string.Format(
|
|||
|
|
"Status={0}, ActiveRequestId={1}, CurrentAction={2}, SourceStepId={3}, IsChipLoaded={4}",
|
|||
|
|
snapshot.Status,
|
|||
|
|
NormalizeLogValue(snapshot.ActiveRequestId),
|
|||
|
|
snapshot.CurrentAction,
|
|||
|
|
NormalizeLogValue(snapshot.SourceStepId),
|
|||
|
|
snapshot.IsChipLoaded);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string BuildAlarmTriggerSummary(ChipPreparationRequest request, ChipPreparationWaitResult executeResult)
|
|||
|
|
{
|
|||
|
|
return string.Format(
|
|||
|
|
"{0}, ErrorMessage={1}",
|
|||
|
|
BuildRequestSummary(request),
|
|||
|
|
executeResult == null ? "N/A" : NormalizeLogValue(executeResult.ErrorMessage));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string NormalizeLogValue(string value)
|
|||
|
|
{
|
|||
|
|
return string.IsNullOrWhiteSpace(value) ? "N/A" : value;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class ChipPreparationExecuteActivity : ActivityAbstractBase
|
|||
|
|
{
|
|||
|
|
private readonly ChipPreparationRequest _request;
|
|||
|
|
|
|||
|
|
public ChipPreparationExecuteActivity(string name, ChipPreparationRequest request)
|
|||
|
|
: base(name)
|
|||
|
|
{
|
|||
|
|
_request = request;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override async Task<ActivityResult> OnExecuteAsync(WorkflowContext context, ActivityControl activityControl)
|
|||
|
|
{
|
|||
|
|
if (_request == null)
|
|||
|
|
{
|
|||
|
|
return ActivityResult.Failure;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (int i = 0; i < 3; i++)
|
|||
|
|
{
|
|||
|
|
activityControl.ThrowIfCancellationRequested();
|
|||
|
|
await activityControl.CheckPauseAsync();
|
|||
|
|
await Task.Delay(300, activityControl.CancellationToken);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ActivityResult.Success;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|