private void TrackWorkflowInstanceRecord(WorkflowInstanceRecord workflowInstanceRecord, ActualTrace _trace) { WorkflowInstanceState workflowInstanceState = (WorkflowInstanceState)Enum.Parse(typeof(WorkflowInstanceState), workflowInstanceRecord.State); WorkflowInstanceTrace workflowInstanceTrace = new WorkflowInstanceTrace(workflowInstanceRecord.InstanceId, workflowInstanceRecord.WorkflowDefinitionIdentity, workflowInstanceState); _trace.Add(workflowInstanceTrace); }
async Task <object> ContinueState(SuspendState state, WorkflowInstanceState workflowstate, WorkableLogger tasklogger, IDictionary <string, object> variables, CancellationToken token) { object lastresult = null; if (state.Subflow != null) { WorkflowIdentifier workflow = workflowstate.Workflow; workflowstate.Workflow = state.Subflow.Workflow; lastresult = await ContinueState(state.Subflow, workflowstate, tasklogger, variables, token); workflowstate.Workflow = workflow; } else { if (variables != null) { foreach (KeyValuePair <string, object> entry in variables) { state.Variables[entry.Key] = entry.Value.DetermineValue(state.Variables); } } } InstanceTransition transition = await EvaluateTransitions(state.Node, tasklogger, state.Variables, state.Node.Transitions, token); if (transition == null) { tasklogger.Warning("Suspend node has no transition defined for current state. Workflow ends by default."); return(lastresult); } return(await Execute(workflowstate, token, transition.Target, lastresult)); }
/// <inheritdoc /> public async Task <WorkableTask> Execute(WorkflowInstance workflow, IDictionary <string, object> arguments, bool profiling, TimeSpan?wait = null) { WorkableTask task = taskservice.CreateTask(WorkableType.Workflow, workflow.Id, workflow.Revision, workflow.Name, arguments); WorkableLogger tasklogger = new WorkableLogger(logger, task); try { task.Task = Task.Run(() => { StateVariableProvider variables = new StateVariableProvider(ProcessImports(tasklogger, workflow.StartNode.Parameters?.Imports)); variables.Add(arguments); WorkflowInstanceState workflowstate = new WorkflowInstanceState(new WorkflowIdentifier(workflow.Id, workflow.Revision, workflow.Name), tasklogger, variables, GetWorkflowInstance, this, workflow.Language, profiling); return(Execute(workflowstate, task.Token.Token, workflow.StartNode)); }).ContinueWith(t => HandleTaskResult(t, task, tasklogger)); } catch (Exception e) { tasklogger.Error("Failed to execute workflow", e); task.Finished = DateTime.Now; task.Status = TaskStatus.Failure; await taskservice.FinishTask(task.Id); } if (wait.HasValue && !task.Task.IsCompleted) { await Task.WhenAny(task.Task, Task.Delay(wait.Value)); } return(task); }
/// <inheritdoc /> public override async Task <object> Execute(WorkflowInstanceState state, CancellationToken token) { logparameter ??= await compiler.CompileCodeAsync(Parameters.Text, state.Language ?? ScriptLanguage.NCScript); state.Logger.Log(Parameters.Type, await logparameter.ExecuteAsync <string>(state.Variables, token)); return(null); }
public void Transfer(WorkflowInstanceState state, string instanceID) { base.Connection.Execute(ResourceManage.SQL_WORKFLOW_INSTANCE_UPDATE_TRANSFER, new { State = state.ToString(), InstanceID = instanceID }); }
/// <inheritdoc /> public override async Task <object> Execute(WorkflowInstanceState state, CancellationToken token) { CompiledScript script = await compiler.CompileScriptAsync(Name); IDictionary <string, object> arguments = await Arguments.EvaluateArguments(state.Variables, token); state.Logger.Info($"Executing script '{script.Name}'", string.Join("\n", arguments.Select(p => $"{p.Key}: {p.Value}"))); return(await script.Instance.ExecuteAsync(new VariableProvider(state.Variables, arguments), token)); }
public void Transfer(WorkflowInstanceState state, string instanceID) { using ISession session = DbFactory.OpenSession(); WorkflowInstance instance = session.Get <WorkflowInstance>(instanceID); instance.State = state; session.Update(instance); session.Flush(); }
public void Transfer(WorkflowInstanceState state, string instanceID) { string update = " UPDATE T_INSTANCE SET State=@State WHERE InstanceID=@InstanceID "; base.Connection.Execute(update, new { State = state.ToString(), InstanceID = instanceID }); }
/// <inheritdoc /> public override Task <object> Execute(WorkflowInstanceState state, CancellationToken token) { if (!string.IsNullOrEmpty(Parameters.Variable)) { state.Variables[Parameters.Variable] = null; } SuspendState suspendstate = new SuspendState(state.Workflow, this, state.Variables, state.Language, state.Profiling); return(Task.FromResult((object)suspendstate)); }
// If the resumption didn't timed out nor aborted, but not found, it tries to return the previous response parameter if the operation was idempotent, // ie. throws OperationRepeatedException, or throws InvalidOperationException if the previous response is not known (didn't happen or not idempotent). private async Task <TResponseParameter> ResumeOperationBookmarkAsync <TResponseParameter>(string operationName, object requestResult, Type responseParameterType) where TResponseParameter : class { await WaitIdleAsync(Parameters.ResumeOperationTimeout); try { await PrepareAsync(); if (completionState == null) { TaskCompletionSource <TResponseParameter> taskCompletionSource = new TaskCompletionSource <TResponseParameter>(); BookmarkResumptionResult result = await instance.ScheduleOperationBookmarkResumptionAsync(operationName, new object[] { taskCompletionSource, requestResult }); WorkflowInstanceState workflowInstanceState = instance.WorkflowInstanceState; if (result == BookmarkResumptionResult.Success) { try { activeTaskCompletionSources.Add(taskCompletionSource); await instance.RunAsync(); return(await taskCompletionSource.Task); } finally { activeTaskCompletionSources.Remove(taskCompletionSource); } } else { if (result == BookmarkResumptionResult.NotReady && workflowInstanceState != WorkflowInstanceState.Complete) { // Instance is created but the initialization RunAsync() hasn't been called, this is impossible. throw new InvalidOperationException($"Instance state is '{workflowInstanceState}', instance is not ready to process operation '{operationName}'."); } else // NotFound or NotReady && Complete, though the later is also not possible at this point, completionState != null after prepare in that case { throw previousResponseParameterExtension.CreatePreviousResponseParameterException <TResponseParameter>(operationName, responseParameterType); } } } else { throw previousResponseParameterExtension.CreatePreviousResponseParameterException <TResponseParameter>(operationName, responseParameterType); } } catch { // TODO shouldn't we only set idle, if RunAsync() wasn't successful and instance.WorkflowInstanceState != WorkflowInstanceState.Runnable ??? idle.Set(); throw; } }
// don't use "this" to make it a real extension method, don't box enums public static bool ShouldSave(IdlePersistenceMode idlePersistenceMode, WorkflowInstanceState workflowInstanceState, bool isStarting) { if (workflowInstanceState == WorkflowInstanceState.Idle) if (isStarting) return idlePersistenceMode.HasFlag(IdlePersistenceMode.OnStart); else return idlePersistenceMode.HasFlag(IdlePersistenceMode.OnPersistableIdle); if (workflowInstanceState == WorkflowInstanceState.Complete) return idlePersistenceMode.HasFlag(IdlePersistenceMode.OnCompleted); return false; }
async Task <IEnumerator> CreateEnumerator(WorkflowInstanceState state, CancellationToken token) { IScript enumerationscript = await compiler.CompileCodeAsync(Parameters.Collection, state.Language ?? ScriptLanguage.NCScript); object collection = await enumerationscript.ExecuteAsync(state.Variables, token); if (!(collection is IEnumerable enumerable)) { throw new WorkflowException("Can not enumerate null"); } return(enumerable.GetEnumerator()); }
private async Task ResumeReminderBookmarkAsync(string reminderName) { await WaitIdleAsync(Parameters.ResumeInfrastructureTimeout); try { await PrepareAsync(); if (completionState == null) { BookmarkResumptionResult result = await instance.ScheduleReminderBookmarkResumptionAsync(reminderName); WorkflowInstanceState workflowInstanceState = instance.WorkflowInstanceState; if (result == BookmarkResumptionResult.Success) { await instance.RunAsync(); } else { if (result == BookmarkResumptionResult.NotReady && workflowInstanceState != WorkflowInstanceState.Complete) { // Instance is created but the initialization RunAsync() hasn't been called, this is impossible. throw new InvalidOperationException($"Instance state is '{workflowInstanceState}', instance is not ready to process reminder '{reminderName}'."); } else // NotFound or NotReady && Complete, though the later is also not possible at this point, completionState != null after prepare in that case // If we don't find a reminder, it's not an issue, maybe the grain/silo crashed after the reminder was created but before the workflow state was persisted, // or the grain/silo crashed after persistence but before the reminder was unregistered, // it will be unregistered on the next persistence event. // See ReminderTable for the detailed description of the algorithm. { idle.Set(); } } } else { await grain.UnregisterReminderAsync(reminderName); idle.Set(); } } catch { // TODO shouldn't we only set idle, if RunAsync() wasn't successful and instance.WorkflowInstanceState != WorkflowInstanceState.Runnable ??? idle.Set(); throw; } }
/// <inheritdoc /> public override async Task <object> Execute(WorkflowInstanceState state, CancellationToken token) { WorkflowInstance instance = await state.GetWorkflow(parameters.Name); WorkflowIdentifier parent = state.Workflow; state.Workflow = new WorkflowIdentifier(instance.Id, instance.Revision, instance.Name); object result = await state.WorkflowExecutor.Execute(instance, state.Logger, await Arguments.EvaluateArguments(state.Variables, token), state.Profiling, token); state.Workflow = parent; if (result is SuspendState suspend) { result = new SuspendState(state.Workflow, this, state.Variables, state.Language, state.Profiling, suspend); } return(result); }
/// <inheritdoc /> public override async Task <object> Execute(WorkflowInstanceState state, CancellationToken token) { IEnumerator current = state.GetNodeData <IEnumerator>(NodeId); if (current == null) { state[NodeId] = current = await CreateEnumerator(state, token); } if (current.MoveNext()) { state.Variables[Parameters.Item ?? "item"] = current.Current; return(new LoopCommand()); } state.RemoveNodeData(NodeId); return(null); }
/// <inheritdoc /> public override async Task <object> Execute(WorkflowInstanceState state, CancellationToken token) { expression ??= await compiler.CompileCodeAsync(GenerateCode(state.Language ?? ScriptLanguage.NCScript), state.Language ?? ScriptLanguage.NCScript); object result = await expression.ExecuteAsync(state.Variables, token); if (result is Task task) { await task; PropertyInfo resultproperty = task.GetType().GetProperty("Result"); if (resultproperty != null) { return(resultproperty.GetValue(task)); } return(null); } return(result); }
// don't use "this" to make it a real extension method, don't box enums public static bool ShouldSave(IdlePersistenceMode idlePersistenceMode, WorkflowInstanceState workflowInstanceState, bool isStarting) { if (workflowInstanceState == WorkflowInstanceState.Idle) { if (isStarting) { return(idlePersistenceMode.HasFlag(IdlePersistenceMode.OnStarting)); } else { return(idlePersistenceMode.HasFlag(IdlePersistenceMode.OnPersistableIdle)); } } if (workflowInstanceState == WorkflowInstanceState.Complete) { return(idlePersistenceMode.HasFlag(IdlePersistenceMode.OnCompleted)); } return(false); }
private async Task ResumeReminderBookmarkAsync(string reminderName) { BookmarkResumptionResult result = await ScheduleAndRunInstanceAsync(Parameters.ResumeInfrastructureTimeout, () => instance.ScheduleReminderBookmarkResumptionAsync(reminderName), (_result) => _result == BookmarkResumptionResult.Success); WorkflowInstanceState workflowInstanceState = instance.WorkflowInstanceState; if (result == BookmarkResumptionResult.NotReady && workflowInstanceState != WorkflowInstanceState.Complete) { // Instance is created but the initialization RunAsync() hasn't been called, this is impossible. throw new InvalidOperationException($"Instance state is '{workflowInstanceState}', instance is not ready to process reminder '{reminderName}'."); } //else // NotFound, Complete or Success // If we don't find a reminder, it's not an issue, maybe the grain/silo crashed after the reminder was created but before the workflow state was persisted, // or the grain/silo crashed after persistence but before the reminder was unregistered, // it will be unregistered on the next persistence event. // See ReminderTable for the detailed description of the algorithm. }
public FinalTraceSubscription(Guid instanceId, ManualResetEvent mre, int numOccurences, bool hasPersistence, WorkflowInstanceState finalState) { this.manualResetEvent = mre; _numOccurences = numOccurences; // If there is no persistence provider wait for the completed trace _expectedFinalState = finalState; // Also wait for the deleted if (hasPersistence) { _numOccurences++; } _waitingForDeleted = hasPersistence; _instanceId = instanceId; //Log.TraceInternal(String.Format("[FinalTraceSubscription]Instance {0} Waiting for {1}.", instanceId, (hasPersistence)?"Deleted":finalState.ToString())); }
/// <inheritdoc /> public async Task <object> Execute(WorkflowInstanceState state, CancellationToken token) { object result = await node.Execute(state, token); if (operation != null) { if (result != null) { if (!state.Variables.TryGetValue(VariableName, out object lhs)) { lhs = result is string? "" : Activator.CreateInstance(result.GetType()); } result = await operation.ExecuteAsync(new VariableProvider(state.Variables, new Variable("lhs", lhs), new Variable("rhs", result)), token); } } state.Variables[VariableName] = result; return(result); }
public void WaitForTerminalState(WorkflowInstanceState expected, bool validate, int numOccurences) { WaitForFinalTrace(expected, numOccurences); if (this.ExpectedInstanceTraces == null) { this.ExpectedTraces.AddIgnoreTypes(false, typeof(WorkflowInstanceTrace)); } if (validate) { if (this.ExpectedInstanceTraces == null) { ValidateTrackingAndTracing(this.ExpectedTraces); } else { ValidateTrackingAndTracing(this.ExpectedTraces, this.ExpectedInstanceTraces); } } }
/// <inheritdoc /> public async Task <WorkableTask> Continue(Guid taskid, IDictionary <string, object> variables = null, TimeSpan?wait = null) { WorkableTask task = await taskservice.GetTask(taskid); if (task.Status != TaskStatus.Suspended) { throw new ArgumentException($"Task '{taskid}' is not suspended."); } if (task.SuspensionState == null) { throw new InvalidOperationException($"Task '{taskid}' has no suspension state linked to it."); } WorkableLogger tasklogger = new WorkableLogger(logger, task); tasklogger.Info("Resuming execution of workflow", string.Join("\n", variables?.Select(p => $"{p.Key}={p.Value}") ?? new string[0])); try { task.Status = TaskStatus.Running; task.Task = Task.Run(async() => { WorkflowInstanceState workflowstate = new WorkflowInstanceState(task.SuspensionState.Workflow, tasklogger, task.SuspensionState.Variables, GetWorkflowInstance, this, task.SuspensionState.Language, task.SuspensionState.Profiling); return(await ContinueState(task.SuspensionState, workflowstate, tasklogger, variables, task.Token.Token)); }).ContinueWith(t => HandleTaskResult(t, task, tasklogger)); } catch (Exception e) { tasklogger.Error("Failed to execute workflow", e); task.Finished = DateTime.Now; task.Status = TaskStatus.Failure; await taskservice.FinishTask(task.Id); } if (wait.HasValue && !task.Task.IsCompleted) { await Task.WhenAny(task.Task, Task.Delay(wait.Value)); } return(task); }
// Returns true if no aborted or unhandled exception internal void WaitForFinalTrace(WorkflowInstanceState state, int numOccurences) { // If not using the DefaultTracking configuration, then we need to wait for a user trace. The reason is that // InMemoryTrackingParticipant, unlike SQL, pushed traces to the subscription. SQL however is pull only, // so the subscription will hang forever. The workaround is in the Tracking tests wait for the synchronize trace // since it is a user trace and we will always get it. if (!TestTraceManager.IsDefaultTrackingConfiguration) { WaitForSynchronizeTrace(numOccurences); } else { ManualResetEvent mre = new ManualResetEvent(false); FinalTraceSubscription subscription = new FinalTraceSubscription(_workflowInstanceId, mre, numOccurences, _hasPersistenceProvider, state); TestTraceManager.Instance.AddSubscription(_workflowInstanceId, subscription); if (!mre.WaitOne(TimeSpan.FromSeconds(TestTraceManager.MaximumNumberOfSecondsToWaitForATrace))) { throw new TimeoutException(string.Format("Waited for {0} seconds in WaitForFinalTrace without getting the expeced trace of {1}", TestTraceManager.MaximumNumberOfSecondsToWaitForATrace, state.ToString())); } subscription.CheckIfSuccessful(); } }
// If the resumption didn't timed out nor aborted, but not found, it tries to return the previous response parameter if the operation was idempotent, // ie. throws RepeatedOperationException, or throws InvalidOperationException if the previous response is not known (didn't happen or not idempotent). private async Task ResumeOperationBookmarkAsync <TResponseParameter>(string operationName, TaskCompletionSource <TResponseParameter> taskCompletionSource, object requestResult, Type responseParameterType, Func <object, RepeatedOperationException> createRepeatedOperationException) where TResponseParameter : class { BookmarkResumptionResult result = await ScheduleAndRunInstanceAsync(Parameters.ResumeOperationTimeout, () => instance.ScheduleOperationBookmarkResumptionAsync(operationName, new object[] { taskCompletionSource, requestResult }), (_result) => _result == BookmarkResumptionResult.Success, taskCompletionSource); WorkflowInstanceState workflowInstanceState = instance.WorkflowInstanceState; if (result == BookmarkResumptionResult.NotFound || result == BookmarkResumptionResult.NotReady && workflowInstanceState == WorkflowInstanceState.Complete) { previousResponseParameterExtension.ThrowPreviousResponseParameter(operationName, responseParameterType, createRepeatedOperationException); } else if (result == BookmarkResumptionResult.NotReady) // && !Complete // Instance is created but the initialization RunAsync() hasn't been called, this is impossible. { throw new InvalidOperationException($"Instance state is '{workflowInstanceState}', instance is not ready to process operation '{operationName}'."); } //else // Success }
public WorkflowInstanceTrace(Guid instanceName, WorkflowIdentity workflowDefintionIdentity, WorkflowInstanceState instanceStatus) { _instanceName = instanceName; _instanceStatus = instanceStatus; _workflowDefintionIdentity = workflowDefintionIdentity; }
public WorkflowInstanceTrace(Guid instanceName, WorkflowInstanceState instanceStatus) : this(instanceName, null, instanceStatus) { }
public WorkflowInstanceTrace(WorkflowIdentity workflowDefintionIdentity, WorkflowInstanceState instanceStatus) : this(Guid.Empty, workflowDefintionIdentity, instanceStatus) { }
public WorkflowInstanceTrace(WorkflowInstanceState instanceStatus) : this(Guid.Empty, null, instanceStatus) { }
public static void Trace(Guid workflowInstanceId, WorkflowIdentity workflowDefinitionIdentity, WorkflowInstanceState state) { WorkflowInstanceTrace trace = new WorkflowInstanceTrace(workflowInstanceId, workflowDefinitionIdentity, state); TraceSource ts = new TraceSource("CoreWf.Tracking", SourceLevels.Information); ts.TraceData(TraceEventType.Information, 1, trace); }
/// <summary> /// Constructor with instance id and state. /// </summary> /// <param name="id">The workflow Id.</param> /// <param name="state">The state of workflow</param> /// <param name="unhandledException">The unhandled exception, occurs when streams are closed.</param> internal WorkflowStatusEventArgs(Guid id, WorkflowInstanceState state, Exception unhandledException) { this.id = id; this.state = state; this.unhandledException = unhandledException; }
public WorkflowHandlingResponse StartWorkflow( WorkflowStartInfo startInfo) { WorkflowFindData workflowFindData = new WorkflowFindData() { StartType = startInfo.StartType, Code = startInfo.Code }; WorkflowInfo wfInfo = this.FindWorkflow(workflowFindData); if (wfInfo == null) { throw new WorkflowException(string.Format("workflow with code: '{0}' not found", (object)workflowFindData.Code)); } using (UnitOfWork unitOfWork = new UnitOfWork((IDataContextAsync) new WorkflowDbContext())) { WorkflowStep workflowStep = unitOfWork.RepositoryAsync <WorkflowStep>().Queryable(false, true, (List <Expression <Func <WorkflowStep, object> > >)null).Where <WorkflowStep>((Expression <Func <WorkflowStep, bool> >)(wfStep => (int)wfStep.StepType == 1 && wfStep.WorkflowInfoId == wfInfo.ID)).SingleOrDefault <WorkflowStep>(); if (workflowStep == null) { throw new WorkflowException(string.Format("no start step for workflow with code '{0}'", (object)startInfo.Code)); } int?nullable = startInfo.StarterOrganizationId; if (!nullable.HasValue && SecurityManager.CurrentUserContext != null) { startInfo.StarterOrganizationId = SecurityManager.CurrentUserContext.OrganizationId; } if (startInfo.ExchangeData == null) { startInfo.ExchangeData = new WFExchangeData(); } List <WorkflowInstanceState> workflowInstanceStateList = new List <WorkflowInstanceState>(); WorkflowInstanceState workflowInstanceState1 = new WorkflowInstanceState(); workflowInstanceState1.AccomplishTime = new DateTime?(DateTime.Now); workflowInstanceState1.ExchangeData = (string)startInfo.ExchangeData; workflowInstanceState1.InstantiationTime = DateTime.Now; workflowInstanceState1.ObjectState = ObjectState.Added; nullable = new int?(); workflowInstanceState1.SenderWorkflowInstanceStateId = nullable; workflowInstanceState1.UserComment = "شروع فرایند"; workflowInstanceState1.StateStatus = WfStateStatus.Close; workflowInstanceState1.Title = string.Format("شروع فرایند {0} {1}", (object)wfInfo.Title, (object)startInfo.InstanceTitle); workflowInstanceState1.UserId = startInfo.StarterUserId; workflowInstanceState1.WorkflowStepId = workflowStep.ID; WorkflowInstanceState workflowInstanceState2 = workflowInstanceState1; workflowInstanceStateList.Add(workflowInstanceState2); WFExchangeData wfExchangeData1 = new WFExchangeData(); WFExchangeData wfExchangeData2 = wfExchangeData1; nullable = startInfo.StarterOrganizationId; ref int?local1 = ref nullable; int num; string str1; if (!local1.HasValue) { str1 = (string)null; } else { num = local1.GetValueOrDefault(); str1 = num.ToString(); } wfExchangeData2.Add("_StarterOrganizationId_", str1); WFExchangeData wfExchangeData3 = wfExchangeData1; num = startInfo.StarterUserId; string str2 = num.ToString(); wfExchangeData3.Add("_StarterUserId_", str2); wfExchangeData1.Add("_InstanceTitle_", string.Format("{0}", (object)startInfo.InstanceTitle)); wfExchangeData1.Add("_WorkflowTitle_", string.Format("{0}", (object)wfInfo.Title)); wfExchangeData1.Add("_RelatedRecordId_", string.Format("{0}", (object)startInfo.RelatedRecordId)); bool flag = false; WorkflowStep currentStep = workflowStep; WFExchangeData exchangeData = startInfo.ExchangeData; WorkflowInstanceState senderInstanceState = workflowInstanceState2; WFExchangeData initialExchangeData = wfExchangeData1; nullable = new int?(); int? actionId = nullable; ref bool local2 = ref flag;
private void AddWorkflowInstanceTrace(TraceEventType eventType, Guid instanceId, WorkflowIdentity workflowDefintionIdentity, WorkflowInstanceState instanceStatus) { WorkflowInstanceTrace trace = new WorkflowInstanceTrace(instanceId, workflowDefintionIdentity, instanceStatus); this.TestTraceManager.AddTrace(instanceId, trace); if (workflowDefintionIdentity != null) { TestTraceManager.OptionalLogTrace(string.Format("[TestTrackingParticipantBase]{0} : {1} : {2,-11} : {3}", instanceId, workflowDefintionIdentity, eventType, instanceStatus)); } else { TestTraceManager.OptionalLogTrace(string.Format("[TestTrackingParticipantBase]{0} : {1,-11} : {2}", instanceId, eventType, instanceStatus)); } }