From 0b81bba3d40cccd62ce6a03775445039ac07ee2b Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Tue, 17 Nov 2020 22:13:55 +0100 Subject: [PATCH] Fix TimerEvent and CronEvent --- .../Activities/CronEvent/CronEvent.cs | 33 ++++++++++++++++++- .../Activities/TimerEvent/TimerEvent.cs | 23 ++++++++++++- .../Triggers/CronEventTrigger.cs | 17 +--------- .../Triggers/TimerEventTrigger.cs | 17 ++-------- .../Extensions/WorkflowBlueprintExtensions.cs | 7 ++-- 5 files changed, 62 insertions(+), 35 deletions(-) diff --git a/src/activities/Elsa.Activities.Timers/Activities/CronEvent/CronEvent.cs b/src/activities/Elsa.Activities.Timers/Activities/CronEvent/CronEvent.cs index 1b83866ce..6ab4dce92 100644 --- a/src/activities/Elsa.Activities.Timers/Activities/CronEvent/CronEvent.cs +++ b/src/activities/Elsa.Activities.Timers/Activities/CronEvent/CronEvent.cs @@ -2,6 +2,8 @@ using Elsa.ActivityResults; using Elsa.Attributes; using Elsa.Services; using Elsa.Services.Models; +using NCrontab; +using NodaTime; // ReSharper disable once CheckNamespace namespace Elsa.Activities.Timers @@ -13,10 +15,39 @@ namespace Elsa.Activities.Timers )] public class CronEvent : Activity { + private readonly IClock _clock; + + public CronEvent(IClock clock) + { + _clock = clock; + } + + [ActivityProperty(Hint = "Specify a CRON expression. See https://crontab.guru/ for help.")] public string CronExpression { get; set; } = "* * * * *"; + + public Instant ExecuteAt + { + get => GetState(); + set => SetState(value); + } + + protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) + { + if (context.WorkflowExecutionContext.IsFirstPass) + return Done(); + + ExecuteAt = GetNextOccurrence(CronExpression); + return Suspend(); + } - protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) => context.WorkflowExecutionContext.IsFirstPass ? (IActivityExecutionResult) Done() : Suspend(); protected override IActivityExecutionResult OnResume() => Done(); + + private Instant GetNextOccurrence(string cronExpression) + { + var schedule = CrontabSchedule.Parse(cronExpression); + var now = _clock.GetCurrentInstant(); + return Instant.FromDateTimeUtc(schedule.GetNextOccurrence(now.ToDateTimeUtc())); + } } } \ No newline at end of file diff --git a/src/activities/Elsa.Activities.Timers/Activities/TimerEvent/TimerEvent.cs b/src/activities/Elsa.Activities.Timers/Activities/TimerEvent/TimerEvent.cs index 5393f02d0..c664b406b 100644 --- a/src/activities/Elsa.Activities.Timers/Activities/TimerEvent/TimerEvent.cs +++ b/src/activities/Elsa.Activities.Timers/Activities/TimerEvent/TimerEvent.cs @@ -10,10 +10,31 @@ namespace Elsa.Activities.Timers [Trigger(Category = "Timers", Description = "Triggers at a specified interval.")] public class TimerEvent : Activity { + private readonly IClock _clock; + + public TimerEvent(IClock clock) + { + _clock = clock; + } + [ActivityProperty(Hint = "An expression that evaluates to a Duration value.")] public Duration Timeout { get; set; } = default!; - protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) => context.WorkflowExecutionContext.IsFirstPass ? (IActivityExecutionResult)Done() : Suspend(); + public Instant ExecuteAt + { + get => GetState(); + set => SetState(value); + } + + protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) + { + if (context.WorkflowExecutionContext.IsFirstPass) + return Done(); + + ExecuteAt = _clock.GetCurrentInstant().Plus(Timeout); + return Suspend(); + } + protected override IActivityExecutionResult OnResume() => Done(); } } \ No newline at end of file diff --git a/src/activities/Elsa.Activities.Timers/Triggers/CronEventTrigger.cs b/src/activities/Elsa.Activities.Timers/Triggers/CronEventTrigger.cs index 6c7f510f2..9928bbebf 100644 --- a/src/activities/Elsa.Activities.Timers/Triggers/CronEventTrigger.cs +++ b/src/activities/Elsa.Activities.Timers/Triggers/CronEventTrigger.cs @@ -13,29 +13,14 @@ namespace Elsa.Activities.Timers.Triggers public class CronEventTriggerProvider : TriggerProvider { - private readonly IClock _clock; - - public CronEventTriggerProvider(IClock clock) - { - _clock = clock; - } - public override async ValueTask GetTriggerAsync(TriggerProviderContext context, CancellationToken cancellationToken) { - var cron = await context.GetActivity().GetPropertyValueAsync(x => x.CronExpression, cancellationToken); - var executeAt = GetNextOccurrence(cron); + var executeAt = context.GetActivity().GetState(x => x.ExecuteAt); return new TimerEventTrigger { ExecuteAt = executeAt }; } - - private Instant GetNextOccurrence(string cronExpression) - { - var schedule = CrontabSchedule.Parse(cronExpression); - var now = _clock.GetCurrentInstant(); - return Instant.FromDateTimeUtc(schedule.GetNextOccurrence(now.ToDateTimeUtc())); - } } } \ No newline at end of file diff --git a/src/activities/Elsa.Activities.Timers/Triggers/TimerEventTrigger.cs b/src/activities/Elsa.Activities.Timers/Triggers/TimerEventTrigger.cs index 55f53d9a1..37b1ed73e 100644 --- a/src/activities/Elsa.Activities.Timers/Triggers/TimerEventTrigger.cs +++ b/src/activities/Elsa.Activities.Timers/Triggers/TimerEventTrigger.cs @@ -1,6 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; -using Elsa.Triggers; +using Elsa.Triggers; using NodaTime; namespace Elsa.Activities.Timers.Triggers @@ -12,18 +10,9 @@ namespace Elsa.Activities.Timers.Triggers public class TimerEventTriggerProvider : TriggerProvider { - private readonly IClock _clock; - - public TimerEventTriggerProvider(IClock clock) + public override ITrigger GetTrigger(TriggerProviderContext context) { - _clock = clock; - } - - public override async ValueTask GetTriggerAsync(TriggerProviderContext context, CancellationToken cancellationToken) - { - var duration = await context.GetActivity().GetPropertyValueAsync(x => x.Timeout, cancellationToken); - var now = _clock.GetCurrentInstant(); - var executeAt = now.Plus(duration); + var executeAt = context.GetActivity().GetState(x => x.ExecuteAt); return new TimerEventTrigger { diff --git a/src/core/Elsa.Abstractions/Extensions/WorkflowBlueprintExtensions.cs b/src/core/Elsa.Abstractions/Extensions/WorkflowBlueprintExtensions.cs index 94703e5df..366631a35 100644 --- a/src/core/Elsa.Abstractions/Extensions/WorkflowBlueprintExtensions.cs +++ b/src/core/Elsa.Abstractions/Extensions/WorkflowBlueprintExtensions.cs @@ -41,7 +41,7 @@ namespace Elsa return (T)value!; } - public static T GetActivityState( + public static T? GetActivityState( this IWorkflowBlueprint workflowBlueprint, Expression> propertyExpression, ActivityExecutionContext activityExecutionContext) where TActivity : IActivity @@ -51,13 +51,14 @@ namespace Elsa return GetActivityState(propertyName, activityExecutionContext); } - public static T GetActivityState( + public static T? GetActivityState( string propertyName, ActivityExecutionContext activityExecutionContext) { var activity = activityExecutionContext.ActivityInstance; var serializer = activityExecutionContext.GetService(); - return activity.Data[propertyName]!.ToObject(serializer)!; + var value = activity.Data[propertyName]; + return value != null ? value.ToObject(serializer) : default; } public static IEnumerable WithVersion(