diff --git a/src/Testing/CoreTests/Runtime/MessageContextTests.cs b/src/Testing/CoreTests/Runtime/MessageContextTests.cs index ced4549e2..dae38ba20 100644 --- a/src/Testing/CoreTests/Runtime/MessageContextTests.cs +++ b/src/Testing/CoreTests/Runtime/MessageContextTests.cs @@ -115,7 +115,7 @@ public async Task reschedule_without_native_scheduling() theEnvelope.ScheduledTime.ShouldBe(scheduledTime); - await theContext.Storage.Inbox.Received().ScheduleJobAsync(theEnvelope); + await theContext.Storage.Inbox.Received().ScheduleExecutionAsync(theEnvelope); } [Fact] @@ -130,11 +130,42 @@ public async Task reschedule_with_native_scheduling() theEnvelope.ScheduledTime.ShouldBe(scheduledTime); - await theContext.Storage.Inbox.DidNotReceive().ScheduleJobAsync(theEnvelope); + await theContext.Storage.Inbox.DidNotReceive().ScheduleExecutionAsync(theEnvelope); await callback.As().Received() .MoveToScheduledUntilAsync(theEnvelope, scheduledTime); } + [Fact] + public async Task reschedule_convenience_method_with_DateTimeOffset() + { + var callback = Substitute.For(); + var scheduledTime = DateTime.Today.AddHours(8); + + theContext.ReadEnvelope(theEnvelope, callback); + + // Test the new convenience extension method + await theContext.RescheduleAsync(scheduledTime); + + theEnvelope.ScheduledTime.ShouldBe(scheduledTime); + await theContext.Storage.Inbox.Received().ScheduleExecutionAsync(theEnvelope); + } + + [Fact] + public async Task reschedule_convenience_method_with_TimeSpan() + { + var callback = Substitute.For(); + var delay = TimeSpan.FromHours(2); + var expectedTime = DateTimeOffset.UtcNow.Add(delay); + + theContext.ReadEnvelope(theEnvelope, callback); + + // Test the new convenience extension method with TimeSpan + await theContext.RescheduleAsync(delay); + + theEnvelope.ScheduledTime.Value.ShouldBeInRange(expectedTime.AddSeconds(-1), expectedTime.AddSeconds(1)); + await theContext.Storage.Inbox.Received().ScheduleExecutionAsync(theEnvelope); + } + [Fact] public async Task move_to_dead_letter_queue_without_native_dead_letter() { diff --git a/src/Wolverine/IMessageBus.cs b/src/Wolverine/IMessageBus.cs index 6063af5ea..93746acb1 100644 --- a/src/Wolverine/IMessageBus.cs +++ b/src/Wolverine/IMessageBus.cs @@ -42,6 +42,32 @@ public static ValueTask ScheduleAsync(this IMessageBus bus, T message, TimeSp options.ScheduleDelay = delay; return bus.PublishAsync(message, options); } + + /// + /// Reschedule the current message being handled to be executed at a later time. + /// This can only be used from within a message handler and will update the existing + /// envelope rather than creating a new one (avoiding duplicate key issues). + /// + /// The message context from within a handler + /// When the message should be executed + /// + public static Task RescheduleAsync(this IMessageContext context, DateTimeOffset scheduledTime) + { + return ((IEnvelopeLifecycle)context).ReScheduleAsync(scheduledTime); + } + + /// + /// Reschedule the current message being handled to be executed after a delay. + /// This can only be used from within a message handler and will update the existing + /// envelope rather than creating a new one (avoiding duplicate key issues). + /// + /// The message context from within a handler + /// How long to delay before executing the message + /// + public static Task RescheduleAsync(this IMessageContext context, TimeSpan delay) + { + return ((IEnvelopeLifecycle)context).ReScheduleAsync(DateTimeOffset.UtcNow.Add(delay)); + } } public interface ICommandBus diff --git a/src/Wolverine/Runtime/MessageContext.cs b/src/Wolverine/Runtime/MessageContext.cs index 03ee366ef..59f0722a5 100644 --- a/src/Wolverine/Runtime/MessageContext.cs +++ b/src/Wolverine/Runtime/MessageContext.cs @@ -139,7 +139,7 @@ public async Task ReScheduleAsync(DateTimeOffset scheduledTime) } else { - await Storage.Inbox.ScheduleJobAsync(Envelope); + await Storage.Inbox.ScheduleExecutionAsync(Envelope); } }