using System.Runtime.CompilerServices; using Elsa.Common; using Elsa.Expressions.Models; using Elsa.Extensions; using Elsa.Scheduling.Bookmarks; using Elsa.Workflows; using Elsa.Workflows.Attributes; using Elsa.Workflows.Memory; using Elsa.Workflows.Models; using Microsoft.Extensions.Logging; namespace Elsa.Scheduling.Activities; /// /// Triggers the workflow at a specific future timestamp. /// [Activity("Elsa", "Scheduling", "Trigger execution at a specific time in the future.")] public class StartAt : Trigger { private const string InputKey = "ExecuteAt"; /// public StartAt([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, line) { } /// public StartAt(Input dateTime, [CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : this(source, line) => DateTime = dateTime; /// public StartAt(Func dateTime, [CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : this(new Input(dateTime), source, line) { } /// public StartAt( Func> dateTime, [CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : this(new Input(dateTime), source, line) { } /// public StartAt(Func> dateTime, [CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : this(new Input(dateTime), source, line) { } /// public StartAt(Func dateTime, [CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : this(new Input(dateTime), source, line) { } /// public StartAt(DateTimeOffset dateTime, [CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : this(source, line) => DateTime = new Input(dateTime); /// public StartAt(Variable dateTime, [CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : this(source, line) => DateTime = new Input(dateTime); /// /// The timestamp at which the workflow should be triggered. /// [Input] public Input DateTime { get; set; } = null!; /// protected override object GetTriggerPayload(TriggerIndexingContext context) { var executeAt = context.ExpressionExecutionContext.Get(DateTime); return new StartAtPayload(executeAt); } /// protected override async ValueTask ExecuteAsync(ActivityExecutionContext context) { if (context.IsTriggerOfWorkflow()) { await context.CompleteActivityAsync(); return; } var executeAt = context.ExpressionExecutionContext.Get(DateTime); var clock = context.ExpressionExecutionContext.GetRequiredService(); var now = clock.UtcNow; var logger = context.GetRequiredService>(); context.JournalData.Add("Executed At", now); if (executeAt <= now) { logger.LogDebug("Scheduled trigger time lies in the past ('{Delta}'). Completing immediately", now - executeAt); await context.CompleteActivityAsync(); return; } var payload = new StartAtPayload(executeAt); context.CreateBookmark(payload); } /// /// Creates a new activity set to trigger at the specified timestamp. /// public static StartAt From(DateTimeOffset value, [CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) => new(value, source, line); }