rebus-org / Rebus.AzureServiceBus

:bus: Azure Service Bus transport for Rebus
https://mookid.dk/category/rebus
Other
33 stars 20 forks source link

Deferring a message onto another input queue using azure service bus #49

Closed mclausen closed 4 years ago

mclausen commented 4 years ago

Hi Mookid! During our normal day development we are using rebus all over the place, its pretty awesome but we stumbled into issue regarding deferring message onto another input queue :sweat_smile:

Our Configuration using the latest rebus 5.4.1, using azure service bus one-way configuration

 builder.Services.AddRebus(c => c
    .Logging(l => l.ColoredConsole())
    .Transport(t => t.UseAzureServiceBusAsOneWayClient(Environment.GetEnvironmentVariable("HostingServiceBus")))
    .Routing(r => r.TypeBased()
        .Map<CheckRestoreDatabaseStatusCommand>("hosting-restoredb-checkstatus-input")
    ));

All handy dandy, later we do the following.

await _bus.Defer(TimeSpan.FromMinutes(2), new CheckRestoreDatabaseStatusCommand
{
    EnvironmentId = command.EnvironmentId,
    ContainerName = containerInstanceName,
    ContainerResourceGroup = containerInstanceResourceGroup
});

Since we are using Azure Service Bus, with built in deferral mechanism I would expect that this would just work, however when i run the code i receive and error from rebus telling me Cannot use ourselves as timeout manager because we're a one-way client.

It's a bit odd now that given that no timeout manager would be needed šŸ¤”.

Venturing further into rebus Defer method, I validated that the destination address is correctly set to hosting-restoredb-checkstatus-input, but when Rebus is trying to fetch is internal timeout manager hell breaking loose and the GetTimeoutManagerAddress throwing the exception seen above.

Looking at the issue it seems like rebus first tries to get the address from the central timeout manager (which we haven't, bc ASB), secondly we are trying to get rebus own input queue which also fails because we are a one-way client.

I am unsure what the remedy for this is, because it seems only be an issue with transports which has native deferral support.

Though not pretty, i've found a temporary workaround :)

var time = RebusTime.Now + TimeSpan.FromMinutes(2);
var str = time.ToIso8601DateTimeOffset();

await _bus.Send(new CheckRestoreDatabaseStatusCommand
{
    EnvironmentId = command.EnvironmentId,
    ContainerName = containerInstanceName,
    ContainerResourceGroup = containerInstanceResourceGroup
}, new Dictionary<string, string>()
{
    { Headers.DeferredUntil, str },
    { Headers.DeferredRecipient, "hosting-restoredb-checkstatus-input" }
});

If you happen to have a good solution for suppressing the Cannot use ourselves as timeout manager because we're a one-way client, and using the routing slip when using Azure Service bus, i would be happy to send a PR :smiley:

mclausen commented 4 years ago

Diving into the sweet adventure of Rebus.AzureServiceBus I conjured the following failing unit-test in Rebus.AzureServiceBus.Tests šŸŒµ

[TestFixture]
    public class CanDeferMessageOntoAnotherQueueInOneWayConfiguration : FixtureBase
    {
        BuiltinHandlerActivator _activator;
        IBus _bus;

        protected override void SetUp()
        {
            _activator = new BuiltinHandlerActivator();
            Using (_activator);

            var connectionString = AsbTestConfig.ConnectionString;
            _bus = Configure.With(_activator)
               .Transport(t => t.UseAzureServiceBusAsOneWayClient(connectionString))
               .Routing(r => r.TypeBased().Map<DeferredMessage>("Some-target-queue"));
               .Start();

            Using(_bus);
        }

        [Test]
        public async Task ItWorks()
        {
            Assert.DoesNotThrowAsync(async () => await _bus.Defer(TimeSpan.FromSeconds(5), new DeferredMessage()));
        }

        class DeferredMessage { }
    }

I am still unsure about a solution, but I would expect this test to pass šŸ¤ 

mookid8000 commented 4 years ago

OK, I've figured it out now! šŸ˜ thanks to your bug report and failing test case, I could fix the bug without much trouble.

I'll just let the ci server munch through the tests, and then I'll push the fixed version as Rebus.AzureServiceBus 7.0.0.

Thanks for reporting this issue! šŸ‘

mookid8000 commented 4 years ago

Rebus.AzureServiceBus 7.0.0 is on NuGet.org now! šŸ™‚