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)); }
async Task <WorkableTask> Execute(IScript scriptinstance, WorkableTask scripttask, IDictionary <string, object> variables, TimeSpan?wait) { WorkableLogger scriptlogger = new WorkableLogger(logger, scripttask); scripttask.Task = Execute(scriptinstance, scriptlogger, variables, scripttask.Token.Token).ContinueWith(t => { if (t.IsCanceled) { scriptlogger.Warning("Script execution was aborted"); scripttask.Status = TaskStatus.Canceled; } else if (t.IsFaulted) { scriptlogger.Error("Script failed to execute", t.Exception?.InnerException ?? t.Exception); scripttask.Status = TaskStatus.Failure; } else { scripttask.Result = t.Result; scriptlogger.Info($"Script executed successfully with result '{scripttask.Result}'"); scripttask.Status = TaskStatus.Success; } scripttask.Finished = DateTime.Now; scriptinstances.FinishTask(scripttask.Id).GetAwaiter().GetResult(); }); if (wait.HasValue && !scripttask.Task.IsCompleted) { await Task.WhenAny(scripttask.Task, Task.Delay(wait.Value)); } return(scripttask); }
void HandleTaskResult(Task <object> t, WorkableTask task, WorkableLogger tasklogger) { tasklogger.LogPerformance(); if (t.IsCanceled) { tasklogger.Warning("Workflow execution was aborted"); task.Status = TaskStatus.Canceled; } else if (t.IsFaulted) { tasklogger.Error("Workflow failed to execute", t.Exception?.InnerException ?? t.Exception); task.Status = TaskStatus.Failure; } else { if (t.Result is SuspendState state) { tasklogger.Info($"Workflow was suspended at '{state}'"); task.SuspensionState = state; task.Status = TaskStatus.Suspended; // don't finish task when it gets suspended // else it would get serialized and suspension state is lost // TODO: this could get refactored to allow for state serialization return; } task.Result = t.Result; tasklogger.Info($"Workflow executed successfully with result '{task.Result}'"); task.Status = TaskStatus.Success; } task.Finished = DateTime.Now; taskservice.FinishTask(task.Id).GetAwaiter().GetResult(); }