diff --git a/src/modules/Elsa.Scheduling/ScheduledTasks/ScheduledCronTask.cs b/src/modules/Elsa.Scheduling/ScheduledTasks/ScheduledCronTask.cs
index 25dd3f9a8..349e6b4a1 100644
--- a/src/modules/Elsa.Scheduling/ScheduledTasks/ScheduledCronTask.cs
+++ b/src/modules/Elsa.Scheduling/ScheduledTasks/ScheduledCronTask.cs
@@ -77,8 +77,13 @@ public class ScheduledCronTask : IScheduledTask, IDisposable
private void TrySetupTimer(TimeSpan delay)
{
+ // Handle edge cases where delay is zero or negative (e.g., due to clock drift, fast execution, or time alignment)
+ // Instead of silently returning, use a minimum delay to ensure the timer fires and workflow continues scheduling
if (delay <= TimeSpan.Zero)
- return;
+ {
+ _logger.LogWarning("Calculated delay is {Delay} which is not positive. Using minimum delay of 1ms to ensure timer fires", delay);
+ delay = TimeSpan.FromMilliseconds(1);
+ }
try
{
diff --git a/test/unit/Elsa.Scheduling.UnitTests/ScheduledTasks/ScheduledCronTaskTests.cs b/test/unit/Elsa.Scheduling.UnitTests/ScheduledTasks/ScheduledCronTaskTests.cs
new file mode 100644
index 000000000..9bf59db61
--- /dev/null
+++ b/test/unit/Elsa.Scheduling.UnitTests/ScheduledTasks/ScheduledCronTaskTests.cs
@@ -0,0 +1,189 @@
+using Elsa.Common;
+using Elsa.Mediator.Contracts;
+using Elsa.Scheduling;
+using Elsa.Scheduling.ScheduledTasks;
+using Elsa.Scheduling.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using NSubstitute;
+
+namespace Elsa.Scheduling.UnitTests.ScheduledTasks;
+
+///
+/// Tests for ScheduledCronTask to ensure cron triggers continue to fire even in edge cases.
+///
+public class ScheduledCronTaskTests : IDisposable
+{
+ private const string DefaultCronExpression = "0 */5 * * * *";
+ private static readonly DateTimeOffset DefaultNow = new(2025, 11, 06, 22, 50, 00, 0, TimeSpan.Zero);
+
+ private readonly ServiceCollection _services;
+ private readonly ServiceProvider _serviceProvider;
+ private readonly ISystemClock _systemClock;
+ private readonly ICronParser _cronParser;
+ private readonly ILogger _logger;
+ private readonly List _tasksToDispose = new();
+
+ public ScheduledCronTaskTests()
+ {
+ _services = new ServiceCollection();
+ _systemClock = Substitute.For();
+ _cronParser = Substitute.For();
+ _logger = Substitute.For>();
+
+ _services.AddSingleton(Substitute.For());
+ _serviceProvider = _services.BuildServiceProvider();
+ }
+
+ private ScheduledCronTask CreateScheduledTask(
+ string? cronExpression = null,
+ ICronParser? cronParser = null,
+ ISystemClock? systemClock = null)
+ {
+ var task = Substitute.For();
+ var scheduledTask = new ScheduledCronTask(
+ task,
+ cronExpression ?? DefaultCronExpression,
+ cronParser ?? _cronParser,
+ _serviceProvider.CreateScope().ServiceProvider.GetRequiredService(),
+ systemClock ?? _systemClock,
+ _logger
+ );
+ _tasksToDispose.Add(scheduledTask);
+ return scheduledTask;
+ }
+
+ private void SetupCronParser(params DateTimeOffset[] occurrences)
+ {
+ _cronParser.GetNextOccurrence(Arg.Any()).Returns(occurrences[0], occurrences.Skip(1).ToArray());
+ }
+
+ private void SetupSystemClock(params DateTimeOffset[] times)
+ {
+ _systemClock.UtcNow.Returns(times[0], times.Skip(1).ToArray());
+ }
+
+ private void AssertNoErrorLogged()
+ {
+ _logger.DidNotReceive().Log(
+ LogLevel.Error,
+ Arg.Any(),
+ Arg.Any