New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AdvanceTime with multiple timeouts throws exception #370
Comments
Hi @ngallegos Looking at your repro, I seem to get a different error: Do I have to make further changes to reproduce the error that you're seeing? |
Eesh, I'm sorry, @timbussmann , I think I got caught up in figuring out the problem and didn't realize the other places I'd modified the test. See the full file below, but here's a summary of what else I changed:
Here's the modified file: namespace NServiceBus.Testing.Tests.Sagas
{
using System;
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
[TestFixture]
public class BasicSaga
{
[Test]
public async Task TestBasicSaga()
{
var testableSaga = new TestableSaga<ShippingPolicy, ShippingPolicyData>();
var placeResult = await testableSaga.Handle(new OrderPlaced { OrderId = "abc" });
var billResult = await testableSaga.Handle(new OrderBilled { OrderId = "abc" });
await Task.Delay(1000);
var billResult2 = await testableSaga.Handle(new OrderBilled { OrderId = "abc" });
Assert.That(placeResult.Completed, Is.False);
Assert.That(billResult.Completed, Is.False);
// Snapshots of data should still be assertable even after multiple operations have occurred.
Assert.That(placeResult.SagaDataSnapshot.OrderId, Is.EqualTo("abc"));
Assert.That(placeResult.SagaDataSnapshot.Placed, Is.True);
Assert.That(placeResult.SagaDataSnapshot.Billed, Is.False);
var noResults = await testableSaga.AdvanceTime(TimeSpan.FromMinutes(10));
Assert.That(noResults.Length, Is.EqualTo(0));
var timeoutResults = await testableSaga.AdvanceTime(TimeSpan.FromHours(1));
Assert.That(timeoutResults.Length, Is.EqualTo(1));
var shipped = timeoutResults.First().FindPublishedMessage<OrderShipped>();
Assert.That(shipped.OrderId == "abc");
}
public class ShippingPolicy : NServiceBus.Saga<ShippingPolicyData>,
IAmStartedByMessages<OrderPlaced>,
IAmStartedByMessages<OrderBilled>,
IHandleTimeouts<ShippingDelay>
{
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<ShippingPolicyData> mapper)
{
mapper.MapSaga(saga => saga.OrderId)
.ToMessage<OrderPlaced>(msg => msg.OrderId)
.ToMessage<OrderBilled>(msg => msg.OrderId);
}
public Task Handle(OrderPlaced message, IMessageHandlerContext context)
{
Data.Placed = true;
return TimeToShip(context);
}
public Task Handle(OrderBilled message, IMessageHandlerContext context)
{
Data.Billed = true;
Data.BilledOn = DateTimeOffset.UtcNow;
return TimeToShip(context);
}
public async Task TimeToShip(IMessageHandlerContext context)
{
if (Data.Placed && Data.Billed)
{
await RequestTimeout<ShippingDelay>(context, TimeSpan.FromMinutes(15)
, new ShippingDelay { BilledOn = Data.BilledOn });
}
}
public async Task Timeout(ShippingDelay state, IMessageHandlerContext context)
{
if (Data.BilledOn.Ticks == state.BilledOn.Ticks)
{
await context.Publish(new OrderShipped { OrderId = Data.OrderId });
MarkAsComplete();
}
}
}
public class ShippingPolicyData : ContainSagaData
{
public string OrderId { get; set; }
public bool Placed { get; set; }
public bool Billed { get; set; }
public DateTimeOffset BilledOn { get; set; }
}
public class OrderPlaced : IEvent
{
public string OrderId { get; set; }
}
public class OrderBilled : IEvent
{
public string OrderId { get; set; }
}
public class OrderShipped : IEvent
{
public string OrderId { get; set; }
}
public class ShippingDelay
{
public DateTimeOffset BilledOn { get; set; }
}
}
} |
thanks for the additional details @ngallegos , I'll try to look closer into this as soon as possible. |
@ngallegos I've tried to run the code that you shared but that seems to work without errors. The test is failing due to an assertion but I don't see the exception message that you've described 🤔 |
@timbussmann
Here are the details of the exception:
Just looking now and I see someone's made changes to the problematic code already, so this may be fixed. But in the code I've got
The fixed code is sorting by the timeout
When do you anticipate the next patch being released for this package? |
Thanks @ngallegos and @mikesigs , I wasn't able to reproduce the issue because I ran the repro code against
I can't give you any reliable predictions for the release of the fix. I hope we can make it available to you as soon as possible. |
This is being fixed with NServiceBus.Testing 7.4.1 which should be available on NuGet soon. See the release announcement for further details. Thanks for raising this issue! |
Thanks @timbussmann ! |
Symptoms
Adding another OrderBilledCall (or any new message handler that adds another timeout to the saga) and calling AdvanceTime in this test throws an exception:
To reproduce, I added a second call to handle OrderBilled after the first call:
I know it doesn't make sense to handle order billed twice in a row like this, but this was the easiest way to reproduce the issue. My use case involves the timeout handler taking action depending on some saga data that can be updated by an event being handled multiple times during the life of the saga.
Who's affected
All tests using the
TestableSaga
helper class using theAdvanceTime(...)
API for sagas that have multiple delayed messages and/or timeouts.Root cause
A mistake during backporting this functionality from the
master
branch to therelease-7.4
branch mixed up the tuple properties for anOrderBy
comparison, resulting in incorrect types being compared.The text was updated successfully, but these errors were encountered: