diff --git a/apps/WorkflowEngine.DemoApp/Startup.cs b/apps/WorkflowEngine.DemoApp/Startup.cs index 7574659..dfe4fcf 100644 --- a/apps/WorkflowEngine.DemoApp/Startup.cs +++ b/apps/WorkflowEngine.DemoApp/Startup.cs @@ -303,7 +303,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IService (executor) => executor.TriggerAsync(new TriggerContext { Workflow = workflows.First(), Trigger = new Trigger { ScheduledTime = DateTimeOffset.UtcNow, Key = workflows.First().Manifest.Triggers.First().Key, - Type =workflows.First().Manifest.Triggers.First().Value.Type }, RunId = Guid.NewGuid() })); + Type =workflows.First().Manifest.Triggers.First().Value.Type }, RunId = Guid.NewGuid() },null)); await c.Response.WriteAsync("Background JOb:" + a); @@ -333,7 +333,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IService Key = workflows.First(w => w.Id.ToString() == c.GetRouteValue("id") as string).Manifest.Triggers.FirstOrDefault().Key }, Workflow = workflows.First(w=>w.Id.ToString() == c.GetRouteValue("id") as string) - })); + },null)); await c.Response.WriteAsync("Background JOb:" + a); diff --git a/src/WorkflowEngine.Core/ActionCompletedEvent.cs b/src/WorkflowEngine.Core/ActionCompletedEvent.cs new file mode 100644 index 0000000..64bb803 --- /dev/null +++ b/src/WorkflowEngine.Core/ActionCompletedEvent.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; + +namespace WorkflowEngine.Core +{ + public class ActionCompletedEvent : Event + { + public override EventType EventType => EventType.ActionCompleted; + + [JsonProperty("jobId")] + public string JobId { get; set; } + [JsonProperty("actionKey")] + public string ActionKey { get; set; } + [JsonProperty("resultPath")] + public string ResultPath { get; set; } + + [JsonProperty("status")] + public string Status { get; set; } + + public static ActionCompletedEvent FromAction(IActionResult result,IAction action,string jobId) + { + + return new ActionCompletedEvent + { + + JobId = jobId, + ActionKey = action.Key, + Status = result.Status, + }; + } + } +} diff --git a/src/WorkflowEngine.Core/ActionExecutor.cs b/src/WorkflowEngine.Core/ActionExecutor.cs index d2457d0..f09483c 100644 --- a/src/WorkflowEngine.Core/ActionExecutor.cs +++ b/src/WorkflowEngine.Core/ActionExecutor.cs @@ -1,4 +1,4 @@ -using ExpressionEngine; +using ExpressionEngine; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; @@ -18,32 +18,32 @@ public class ScopeContext : IScopeContext } public class ActionExecutor : IActionExecutor { - private readonly IOutputsRepository outputsRepository; - private readonly IServiceProvider serviceProvider; - private readonly ILogger logger; - private readonly IScopeContext scopeContext; - private readonly IExpressionEngine expressionEngine; + private readonly IOutputsRepository _outputsRepository; + private readonly IServiceProvider _serviceProvider; + private readonly ILogger _logger; + private readonly IScopeContext _scopeContext; + private readonly IExpressionEngine _expressionEngine; private Dictionary _implementations; public ActionExecutor( - IEnumerable implementations, + IEnumerable implementations, IOutputsRepository outputsRepository, IServiceProvider serviceProvider, ILogger logger, IScopeContext scopeContext, IExpressionEngine expressionEngine) { - - if(implementations.GroupBy(k=>k.Type).Any(c=>c.Count() > 1)) + + if (implementations.GroupBy(k => k.Type).Any(c => c.Count() > 1)) { - throw new ArgumentException("Double registration of " + String.Join(",", implementations.GroupBy(k => k.Type).Where(c => c.Count() > 1).Select(c=>c.Key))); + throw new ArgumentException("Double registration of " + String.Join(",", implementations.GroupBy(k => k.Type).Where(c => c.Count() > 1).Select(c => c.Key))); } _implementations = implementations?.ToDictionary(k => k.Type) ?? throw new ArgumentNullException(nameof(implementations)); - this.outputsRepository=outputsRepository??throw new ArgumentNullException(nameof(outputsRepository)); - this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); - this.logger=logger??throw new ArgumentNullException(nameof(logger)); - this.scopeContext=scopeContext; - this.expressionEngine=expressionEngine??throw new ArgumentNullException(nameof(expressionEngine)); + _outputsRepository = outputsRepository ?? throw new ArgumentNullException(nameof(outputsRepository)); + _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _scopeContext = scopeContext; + _expressionEngine = expressionEngine ?? throw new ArgumentNullException(nameof(expressionEngine)); } public async ValueTask ExecuteAsync(IRunContext context, IWorkflow workflow, IAction action) { @@ -52,13 +52,13 @@ public async ValueTask ExecuteAsync(IRunContext context, IWorkflo if (action.ScopeMoveNext) { - await outputsRepository.EndScope(context, workflow, action); + await _outputsRepository.EndScope(context, workflow, action); } var actionMetadata = workflow.Manifest.Actions.FindAction(action.Key); - scopeContext.Scope=action.Key; - action.Inputs = await expressionEngine.ResolveInputs(actionMetadata,logger); - + _scopeContext.Scope = action.Key; + action.Inputs = await _expressionEngine.ResolveInputs(actionMetadata, _logger); + { //if (workflow.Manifest.Actions.FindParentAction(action.Key) is ForLoopActionMetadata parent) //{ @@ -71,37 +71,39 @@ public async ValueTask ExecuteAsync(IRunContext context, IWorkflo //} //else { - await outputsRepository.AddInput(context, workflow, action); + await _outputsRepository.AddInput(context, workflow, action); } } - - var actionImplementation = serviceProvider.GetRequiredService(_implementations[actionMetadata.Type].Implementation) as IActionImplementation; - + + var actionImplementation = _serviceProvider.GetRequiredService(_implementations[actionMetadata.Type].Implementation) as IActionImplementation; - var result = new ActionResult { - Key = action.Key, - Status = "Succeded", - Result = await actionImplementation.ExecuteAsync(context,workflow, action) + + var result = new ActionResult + { + Key = action.Key, + Status = "Succeded", + Result = await actionImplementation.ExecuteAsync(context, workflow, action) }; - - - await outputsRepository.AddAsync(context, workflow, action, result); - + + + await _outputsRepository.AddAsync(context, workflow, action, result); + return result; - - - }catch(Exception ex) + + + } + catch (Exception ex) { - var result= new ActionResult { Key = action.Key, Status = "Failed", FailedReason=ex.ToString(), ReThrow = (ex is InvalidOperationException) }; + var result = new ActionResult { Key = action.Key, Status = "Failed", FailedReason = ex.ToString(), ReThrow = (ex is InvalidOperationException) }; try { - await outputsRepository.AddAsync(context, workflow, action, result); + await _outputsRepository.AddAsync(context, workflow, action, result); } - catch (Exception ) + catch (Exception exx) { } @@ -109,7 +111,7 @@ public async ValueTask ExecuteAsync(IRunContext context, IWorkflo } } } - + } diff --git a/src/WorkflowEngine.Core/DefaultOutputsRepository.cs b/src/WorkflowEngine.Core/DefaultOutputsRepository.cs index 48a7bd4..c7b9a02 100644 --- a/src/WorkflowEngine.Core/DefaultOutputsRepository.cs +++ b/src/WorkflowEngine.Core/DefaultOutputsRepository.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Concurrent; @@ -64,7 +64,7 @@ private JToken GetOrCreateRun(IRunContext context) return Runs.GetOrAdd(context.RunId, (id) => new JObject(new JProperty("actions", new JObject()), new JProperty("triggers", new JObject()))); } - public ValueTask AddAsync(IRunContext context, IWorkflow workflow, ITrigger trigger) + public ValueTask AddTrigger(ITriggerContext context, IWorkflow workflow, ITrigger trigger) { JToken run = GetOrCreateRun(context); @@ -170,7 +170,14 @@ public ValueTask EndScope(IRunContext context, IWorkflow workflow, IAction actio return new ValueTask(); } - public ValueTask StartScope(IRunContext context, IWorkflow workflow, IAction action) + + public ValueTask AddEvent(IRunContext run, IWorkflow workflow, IAction action, Event @event) + { + // Defaults to nothing to not create noise and breaks backwards compatibility + return new ValueTask(); + } + + public ValueTask StartScope(IRunContext context, IWorkflow workflow, IAction action) { JToken run = GetOrCreateRun(context); @@ -197,10 +204,5 @@ public ValueTask AddInput(IRunContext context, IWorkflow workflow, IAction actio return new ValueTask(); } - - - } - - } diff --git a/src/WorkflowEngine.Core/Event.cs b/src/WorkflowEngine.Core/Event.cs new file mode 100644 index 0000000..942305e --- /dev/null +++ b/src/WorkflowEngine.Core/Event.cs @@ -0,0 +1,48 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; +using System; + +namespace WorkflowEngine.Core +{ + public interface IHaveFinisningStatus + { + IActionResult Result { get; } + } + [JsonConverter(typeof(BaseClassConverter))] + public abstract class Event + { + [JsonProperty("eventType")] + [Newtonsoft.Json.JsonConverter(typeof(StringEnumConverter))] + public abstract EventType EventType { get; } + + + } + + public class BaseClassConverter : CustomCreationConverter + { + private EventType _currentObjectType; + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var jobj = JObject.ReadFrom(reader); + _currentObjectType = jobj["eventType"].ToObject(); + return base.ReadJson(jobj.CreateReader(), objectType, existingValue, serializer); + } + + public override Event Create(Type objectType) + { + switch (_currentObjectType) + { + case EventType.ActionCompleted: + return new ActionCompletedEvent(); + case EventType.WorkflowStarted: + return new WorkflowStarteddEvent(); + case EventType.WorkflowFinished: + return new WorkflowFinishedEvent(); + default: + throw new NotImplementedException(); + } + } + } +} diff --git a/src/WorkflowEngine.Core/EventType.cs b/src/WorkflowEngine.Core/EventType.cs new file mode 100644 index 0000000..84fc932 --- /dev/null +++ b/src/WorkflowEngine.Core/EventType.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json.Linq; +using System.Runtime.Serialization; + +namespace WorkflowEngine.Core +{ + public enum EventType + { + [EnumMember(Value = "workflow_started")] + WorkflowStarted = 0, + [EnumMember(Value = "workflow_finished")] + WorkflowFinished = 1, + [EnumMember(Value = "action_completed")] + ActionCompleted = 2 + } +} diff --git a/src/WorkflowEngine.Core/ExpressionEngineExtensions.cs b/src/WorkflowEngine.Core/ExpressionEngineExtensions.cs index 5410c4c..7ce6833 100644 --- a/src/WorkflowEngine.Core/ExpressionEngineExtensions.cs +++ b/src/WorkflowEngine.Core/ExpressionEngineExtensions.cs @@ -1,7 +1,8 @@ -using ExpressionEngine; +using ExpressionEngine; using ExpressionEngine.Functions.Base; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; @@ -24,30 +25,39 @@ public static IServiceCollection AddFunctions(this IServiceCollection services) return services; } - public static async ValueTask> ResolveInputs(this IExpressionEngine engine, ActionMetadata actionMetadata, ILogger logger) + public static async ValueTask> ResolveInputs(this IExpressionEngine engine, IDictionary inputs, ILogger logger) { var resolvedInputs = new Dictionary(); - foreach (var input in actionMetadata.Inputs) + foreach (var input in inputs) { if (input.Value is string str && str.Contains("@")) { - resolvedInputs[input.Key] = await engine.ParseToValueContainer(str); + resolvedInputs[input.Key] = await engine.ParseToValueContainer(input.Value.ToString()); } else { - resolvedInputs[input.Key] = input.Value; - } - //else - //{ + if (input.Value is IDictionary obj) + { + resolvedInputs[input.Key] = await engine.ResolveInputs(obj, logger); + } + else + { + resolvedInputs[input.Key] = input.Value; + } - // logger.LogWarning("{Key}: {Type}", input, inputs[input].GetType()); - //} - // inputs[input] = inputs[input]; + } + } return resolvedInputs; + + } + public static ValueTask> ResolveInputs(this IExpressionEngine engine, ActionMetadata actionMetadata, ILogger logger) + { + return engine.ResolveInputs(actionMetadata.Inputs, logger); + } } } diff --git a/src/WorkflowEngine.Core/IOutputsRepository.cs b/src/WorkflowEngine.Core/IOutputsRepository.cs index 4afcd1f..0f1393f 100644 --- a/src/WorkflowEngine.Core/IOutputsRepository.cs +++ b/src/WorkflowEngine.Core/IOutputsRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; namespace WorkflowEngine.Core @@ -6,16 +6,15 @@ namespace WorkflowEngine.Core public interface IOutputsRepository { ValueTask AddAsync(IRunContext context, IWorkflow workflow, IAction action, IActionResult result); - ValueTask AddAsync(IRunContext context, IWorkflow workflow, ITrigger trigger); + ValueTask AddTrigger(ITriggerContext context, IWorkflow workflow, ITrigger trigger); ValueTask GetTriggerData(Guid id); ValueTask AddInput(IRunContext context, IWorkflow workflow, IAction action); ValueTask GetOutputData(Guid id, string v); ValueTask AddArrayItemAsync(IRunContext run, IWorkflow workflow, string key, IActionResult result); ValueTask AddArrayInput(IRunContext context, IWorkflow workflow, IAction action); - ValueTask StartScope(IRunContext context, IWorkflow workflow, IAction action); + // ValueTask StartScope(IRunContext context, IWorkflow workflow, IAction action); ValueTask AddScopeItem(IRunContext context, IWorkflow workflow, IAction action, IActionResult result); ValueTask EndScope(IRunContext run, IWorkflow workflow, IAction action); + ValueTask AddEvent(IRunContext run, IWorkflow workflow, IAction action, Event @event); } - - } diff --git a/src/WorkflowEngine.Core/ITriggerContext.cs b/src/WorkflowEngine.Core/ITriggerContext.cs index e14658d..a44c763 100644 --- a/src/WorkflowEngine.Core/ITriggerContext.cs +++ b/src/WorkflowEngine.Core/ITriggerContext.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace WorkflowEngine.Core { @@ -7,6 +7,7 @@ public interface ITriggerContext:IRunContext IWorkflow Workflow { get; } ITrigger Trigger { get; set; } + string JobId { get; set; } } diff --git a/src/WorkflowEngine.Core/TriggerContext.cs b/src/WorkflowEngine.Core/TriggerContext.cs index 1b0668a..e5330cf 100644 --- a/src/WorkflowEngine.Core/TriggerContext.cs +++ b/src/WorkflowEngine.Core/TriggerContext.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; @@ -32,7 +32,7 @@ public class TriggerContext : ITriggerContext, IFormattable public string PrincipalId { get; set; } public Guid RunId { get; set; } - + public string JobId { get; set; } public string ToString(string format, IFormatProvider formatProvider) { diff --git a/src/WorkflowEngine.Core/WorkflowExecutor.cs b/src/WorkflowEngine.Core/WorkflowExecutor.cs index 04e957a..bc65b07 100644 --- a/src/WorkflowEngine.Core/WorkflowExecutor.cs +++ b/src/WorkflowEngine.Core/WorkflowExecutor.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using System; using System.Linq; using System.Threading.Tasks; @@ -49,8 +49,8 @@ public ValueTask GetNextAction(IRunContext context, IWorkflow workflow, public async ValueTask Trigger(ITriggerContext context) { - - await outputsRepository.AddAsync(context,context.Workflow, context.Trigger); + + await outputsRepository.AddTrigger(context,context.Workflow, context.Trigger); var action = context.Workflow.Manifest.Actions.SingleOrDefault(c => c.Value.RunAfter?.Count == 0); diff --git a/src/WorkflowEngine.Core/WorkflowFinishedEvent.cs b/src/WorkflowEngine.Core/WorkflowFinishedEvent.cs new file mode 100644 index 0000000..830a78a --- /dev/null +++ b/src/WorkflowEngine.Core/WorkflowFinishedEvent.cs @@ -0,0 +1,39 @@ +using Newtonsoft.Json; + +namespace WorkflowEngine.Core +{ + public abstract class WorkflowEvent : Event + { + [JsonProperty("status")] + public string Status { get; set; } + + [JsonProperty("jobId")] + public string JobId { get; set; } + + + public static WorkflowFinishedEvent CreateFinishedEvent(string jobid, IActionResult result) + { + return new WorkflowFinishedEvent() { JobId = jobid, Status = result.Status, Result = result }; + } + public static WorkflowFinishedEvent CreateStartedEvent(string jobid, string status) + { + return new WorkflowFinishedEvent() { JobId = jobid, Status = status }; + } + } + public class WorkflowFinishedEvent : WorkflowEvent, IHaveFinisningStatus + { + public override EventType EventType => EventType.WorkflowFinished; + + + [JsonIgnore] + public IActionResult Result { get; set; } + + + } + public class WorkflowStarteddEvent : WorkflowEvent + { + public override EventType EventType => EventType.WorkflowStarted; + + + } +} diff --git a/src/WorkflowEngine.Hangfire/HangfireWorkflowExecutor.cs b/src/WorkflowEngine.Hangfire/HangfireWorkflowExecutor.cs index f7c7101..4c6772d 100644 --- a/src/WorkflowEngine.Hangfire/HangfireWorkflowExecutor.cs +++ b/src/WorkflowEngine.Hangfire/HangfireWorkflowExecutor.cs @@ -1,7 +1,6 @@ -using Hangfire; +using Hangfire; using Hangfire.Server; using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -37,7 +36,7 @@ public static string TriggerAsync(this IBackgroundJobClient bac where TTriggerContext : TriggerContext { var job = backgroundJobClient.Enqueue( - (executor) => executor.TriggerAsync(trigger)); + (executor) => executor.TriggerAsync(trigger,null)); return job; @@ -89,58 +88,48 @@ public async ValueTask ExecuteAsync(IRunContext run, IWorkflow workflow, //TODO - avoid sending all workflow over hangfire, so we should lookup the manifest here if not set on workflow form its ID. workflow.Manifest ??= await workflowAccessor.GetWorkflowManifestAsync(workflow); - runContextAccessor.RunContext = run; arrayContext.JobId = context.BackgroundJob.Id; - try { - var result = await actionExecutor.ExecuteAsync(run, workflow, action); - - - - + + await outputRepository.AddEvent(run, workflow, action, ActionCompletedEvent.FromAction(result,action,context.BackgroundJob.Id)); if (result != null) { - var next = await executor.GetNextAction(run, workflow, result); - + await hangfireActionExecutorResultHandler.InspectAsync(run, workflow, result, next); if (next != null) { - var a = backgroundJobClient.Enqueue( + // This is the hangfire ID thingy, this we would like to save + var workflowRunId = backgroundJobClient.Enqueue( (executor) => executor.ExecuteAsync(run, workflow, next, null)); + // result. } else if (workflow.Manifest.Actions.FindParentAction(action.Key) is ForLoopActionMetadata scope) { + var scopeAction = run.CopyTo(new Action { ScopeMoveNext = true, Type = scope.Type, Key = action.Key.Substring(0, action.Key.LastIndexOf('.')), ScheduledTime = DateTimeOffset.UtcNow }); - var scopeaction = run.CopyTo(new Action { ScopeMoveNext = true, Type = scope.Type, Key = action.Key.Substring(0, action.Key.LastIndexOf('.')), ScheduledTime = DateTimeOffset.UtcNow }); - - - var a = backgroundJobClient.Enqueue( - (executor) => executor.ExecuteAsync(run, workflow, scopeaction, null)); - + var workflowRunId = backgroundJobClient.Enqueue( + (executor) => executor.ExecuteAsync(run, workflow, scopeAction, null)); //await outputRepository.EndScope(run, workflow, action); } else if (result.Status == "Failed" && result.ReThrow) { - + await outputRepository.AddEvent(run, workflow, action, WorkflowEvent.CreateFinishedEvent(context.BackgroundJob.Id,result)); throw new InvalidOperationException("Action failed: " + result.FailedReason) { Data = { ["ActionResult"] = result } }; } - - - - - - + else + { + await outputRepository.AddEvent(run, workflow, action, WorkflowEvent.CreateFinishedEvent(context.BackgroundJob.Id, result)); + } } - return result; } catch (InvalidOperationException ex) @@ -148,35 +137,34 @@ public async ValueTask ExecuteAsync(IRunContext run, IWorkflow workflow, context.SetJobParameter("RetryCount", 999); throw; } - - } + /// /// Runs on the background process in hangfire /// - /// + /// /// - public async ValueTask TriggerAsync(ITriggerContext context) + public async ValueTask TriggerAsync(ITriggerContext triggerContext, PerformContext context) { //TODO - avoid sending all workflow over hangfire, - context.Workflow.Manifest ??= await workflowAccessor.GetWorkflowManifestAsync(context.Workflow); - - context.RunId = context.RunId == Guid.Empty ? Guid.NewGuid() : context.RunId; + triggerContext.Workflow.Manifest ??= await workflowAccessor.GetWorkflowManifestAsync(triggerContext.Workflow); - runContextAccessor.RunContext = context; - var action = await executor.Trigger(context); + triggerContext.RunId = triggerContext.RunId == Guid.Empty ? Guid.NewGuid() : triggerContext.RunId; + triggerContext.JobId = context.BackgroundJob.Id; + + runContextAccessor.RunContext = triggerContext; + var action = await executor.Trigger(triggerContext); if (action != null) { //TODO - avoid sending all workflow over hangfire, so we should wipe the workflow.manifest before scheduling and restore it after. - context.Workflow.Manifest = null; - + triggerContext.Workflow.Manifest = null; var a = backgroundJobClient.Enqueue( - (executor) => executor.ExecuteAsync(context, context.Workflow, action, null)); + (executor) => executor.ExecuteAsync(triggerContext, triggerContext.Workflow, action, null)); } return action; } } - } + diff --git a/src/WorkflowEngine.Hangfire/IHangfireWorkflowExecutor.cs b/src/WorkflowEngine.Hangfire/IHangfireWorkflowExecutor.cs index b31d60d..a205d74 100644 --- a/src/WorkflowEngine.Hangfire/IHangfireWorkflowExecutor.cs +++ b/src/WorkflowEngine.Hangfire/IHangfireWorkflowExecutor.cs @@ -1,4 +1,5 @@ -using Hangfire; +using Hangfire; +using Hangfire.Server; using System.ComponentModel; using System.Threading.Tasks; using WorkflowEngine.Core; @@ -8,7 +9,7 @@ namespace WorkflowEngine public interface IHangfireWorkflowExecutor { [JobDisplayName("Trigger: {0:Workflow} RunId={0:Id}")] - public ValueTask TriggerAsync(ITriggerContext context); + public ValueTask TriggerAsync(ITriggerContext triggercontext, PerformContext context); } } diff --git a/src/WorkflowEngine.Hangfire/ScheduledWorkflowTrigger.cs b/src/WorkflowEngine.Hangfire/ScheduledWorkflowTrigger.cs index 8475afb..9466997 100644 --- a/src/WorkflowEngine.Hangfire/ScheduledWorkflowTrigger.cs +++ b/src/WorkflowEngine.Hangfire/ScheduledWorkflowTrigger.cs @@ -1,4 +1,4 @@ -using Hangfire; +using Hangfire; using Hangfire.Client; using Hangfire.Common; using Hangfire.Storage; @@ -55,7 +55,7 @@ public Task Trigger(string externalid, bool create, DateTimeOffset time, var job = _backgroundJobClient.Schedule((executor) => executor.TriggerAsync( new TriggerContext { Workflow = workflow, Trigger = trigger , - }), time); + },null), time); _logger.LogInformation("Created scheduled workflow job {JobID}", job); diff --git a/src/WorkflowEngine.Hangfire/WorkflowStarterBackgroundJob.cs b/src/WorkflowEngine.Hangfire/WorkflowStarterBackgroundJob.cs index 4002660..7b449c3 100644 --- a/src/WorkflowEngine.Hangfire/WorkflowStarterBackgroundJob.cs +++ b/src/WorkflowEngine.Hangfire/WorkflowStarterBackgroundJob.cs @@ -1,4 +1,4 @@ -using Hangfire; +using Hangfire; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; @@ -50,7 +50,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) Type = trigger.Value.Type, Key = trigger.Key }, - }), trigger.Value.Inputs["cronExpression"] as string); + },null), trigger.Value.Inputs["cronExpression"] as string); if (first && trigger.Value.Inputs.ContainsKey("runAtStartup") && (bool)trigger.Value.Inputs["runAtStartup"]) jobs.Trigger(workflow.Id.ToString());