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(); }
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); }
async Task <InstanceTransition> EvaluateTransitions(IInstanceNode current, WorkableLogger tasklogger, IVariableProvider variableprovider, List <InstanceTransition> transitions, CancellationToken token) { if (transitions == null) { return(null); } InstanceTransition transition = null; foreach (InstanceTransition conditionaltransition in transitions.Where(c => c.Condition != null)) { if (await conditionaltransition.Condition.ExecuteAsync <bool>(variableprovider, token)) { transition = conditionaltransition; break; } } if (transition == null) { InstanceTransition[] defaulttransitions = transitions.Where(t => t.Condition == null).ToArray(); if (defaulttransitions.Length > 1) { throw new InvalidOperationException($"More than one default transition defined for '{current.NodeName}'."); } transition = defaulttransitions.FirstOrDefault(); } if (transition?.Log != null) { try { tasklogger.Info(await transition.Log.ExecuteAsync <string>(variableprovider, token)); } catch (Exception e) { tasklogger.Error($"Error executing transition log of '{current.NodeName}'->'{transition.Target?.NodeName}'", e); throw; } } return(transition); }
/// <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); }