rebus-org / Rebus.AzureServiceBus

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

Message entity could not be found #15

Closed MortenChristiansen closed 5 years ago

MortenChristiansen commented 5 years ago

Previously, I had Azure Service Bus working, but after changing some things it stopped working. The problem is that I now get a MessagingEntityNotFoundException in this line when sending messages.

Put token failed. status-code: 404, status-description:
The messaging entity 'sb://studicabus-dev.servicebus.windows.net/sample_events_institutions_departmentaddedtoinstitutionevent__sample_events' could not be found.
TrackingId:6dad0d8e-b35d-44f6-81a4-3cebb29573e1_G33, SystemTracker:studicabus-dev.servicebus.windows.net:sample_events_institutions_departmentaddedtoinstitutionevent__sample_events, Timestamp:9/26/2018 11:00:10 AM.

This link indicates that the exception means that the resource (in this case the topic) does not exist. This seems strange considering my code previously worked. The change that has broken the functionality is that I have merged several Rebus queues into the same project, so my guess is that this causes me to use Rebus in some invalid way where topics are not created before using them.

Is there any particular information about my setup that would be helpful in solving this? The code is .NET Core if it is relevant.

MortenChristiansen commented 5 years ago

It seems I had forgotten to add some initialization logic when merging projects and after adding it back in, the code worked again. I'm not sure under which conditions this error will occur exactly. I'm closing the issue since my problem solved itself, but let me know if you would like any further details - if this is an error that worries you.

mookid8000 commented 5 years ago

Doesn't really worry me that much 😄 thanks for closing it so quickly 👍

RobinVercammen commented 5 years ago

@MortenChristiansen i'm having the same error. I implemented with following https://github.com/rebus-org/Rebus.ServiceProvider/blob/master/Sample.ConsoleApp/Program.cs sample. What did you have to do to make it create topics in Azure? I assume I'm missing the same stuff you missed

mookid8000 commented 5 years ago

Doesn't really worry me that much 😄 (...)

Turns out I was a little bit too rash, when I said I wasn't worried about this.... I just found out that Rebus.AzureServiceBus 6.0.1 has a BUG that makes it impossible to publish to non-existent topics, which is what happens if the publisher publishes stuff before anyone has subscribed.

Rebus.AzureServiceBus 6.0.2 fixes this. I made it so that it simply swallows the MessagingEntityNotFoundException internally, meaning that topics are not actually created until someone subscribes to them.

Thanks for reporting this bug 😨

RobinVercammen commented 5 years ago

Just updated, it indeed swallows the error. So when publishing a message, there are no errors anymore. Thanks! Though it won't create any topics on Azure.

Any comments on following configuration?

 var config = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", false, true)
                .Build();
            var servicebushost = config.GetConnectionString("ServiceBus");

            var services = new ServiceCollection();

            services.AddRebus(configure => configure.Logging(l => l.ColoredConsole(minLevel: LogLevel.Debug))
                .Transport(t => t.UseAzureServiceBus(servicebushost, "subscriber").AutomaticallyRenewPeekLock())
                .Routing(r => r.TypeBased()
                    .MapAssemblyOf<MoveUp>("subscriber")
                    .MapAssemblyOf<TickMessage>("publisher")));
            services.AutoRegisterHandlersFromAssemblyOf<TickMessageHandler>();

            var provider = services.BuildServiceProvider();

            provider.UseRebus();

            System.Console.ReadLine();

I see the following logging:

[INF] Rebus.Routing.TypeBased.TypeBasedRouter (Thread #1): Mapped Input.Messages.MoveUp -> "subscriber"
[INF] Rebus.Routing.TypeBased.TypeBasedRouter (Thread #1): Mapped Gameloop.Messages.TickMessage -> "publisher"
[INF] Rebus.AzureServiceBus.AzureServiceBusTransport (Thread #1): Initializing Azure Service Bus transport with queue "subscriber"
[INF] Rebus.Threading.TaskParallelLibrary.TplAsyncTask (Thread #1): Starting periodic task "CleanupTrackedErrors" with interval 00:00:10
[INF] Rebus.Bus.RebusBus (Thread #1): Setting number of workers to 1
[DBG] Rebus.Bus.RebusBus (Thread #1): Adding worker "Rebus 1 worker 1"
[INF] Rebus.Bus.RebusBus (Thread #1): Bus "Rebus 1" started
[DBG] Rebus.Workers.ThreadPoolBased.ThreadPoolWorker (Rebus 1 worker 1): Starting (threadpool-based) worker "Rebus 1 worker 1"
mookid8000 commented 5 years ago

(...) Though i don't see any topics created on azure.

I intentionally made it so that topics are not created until someone subscribes. This might be cool, or it might not 😁 I am not sure.

It means that code like this will not "pollute" your service bus namespace with loads of unused entities:

while(true) {
    var randomTopicName = Guid.NewGuid().ToString("n");
    await bus.Advanced.Topics.Publish(randomTopicName, "whatever");
}

but OTOH it will not be visible which topics are being published to, where no subscribers have yet subscribed.

RobinVercammen commented 5 years ago

Please correct me if I'm wrong but from what I understand services.AutoRegisterHandlersFromAssemblyOf<TickMessageHandler>(); should create a subscription?

mookid8000 commented 5 years ago

Please correct me if I'm wrong but from what I understand services.AutoRegisterHandlersFromAssemblyOf<TickMessageHandler>(); should create a subscription?

It doesn't – it simply registers all implementations of IHandleMessages<T> from the assembly containing TickMessageHandler in the container. This means that the endpoint is capable of handling messages for which it has handlers, but it doesn't necessarily mean it's going to receive any.

In order to receive published events of some type into your subscriber queue, your subscriber needs to subscribe to them like this:

await bus.Subscribe<SomeEvent>();

This will create a topic for SomeEvent (an Azure Service Bus-safe name, generated out of the fully qualified type name for SomeEvent), and then it will create a subscription beneath that topic and configure the subscription to forward messages to the subscriber queue.

RobinVercammen commented 5 years ago

Allright, thanks for steering me clear :) For my use case I'd like to subscribe 'automatically' when i'm providing a handler. I wrote following piece of code providing that functionality:

public static class RebusExtensions
    {
        public static Action<IBus> AutoRegisterAllHandlers(params Assembly[] autoRegisterAssemblies)
        {
            return (bus) =>
            {
                var allEvents = autoRegisterAssemblies
                    .SelectMany(a => a.GetTypes().SelectMany(t => t.GetInterfaces()))
                    .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHandleMessages<>))
                    .Select(t => t.GenericTypeArguments.Single())
                    .Select(bus.Subscribe)
                    .ToArray();
                Task.WaitAll(allEvents);
            };
        }

        public static IServiceProvider UseRebus(this IServiceProvider provider,
            params Assembly[] autoRegisterAssemblies)
        {
            return provider.UseRebus(AutoRegisterAllHandlers(autoRegisterAssemblies));
        }
     }

Any remarks on why this might be a bad idea? I'd appreciate any feedback.

mookid8000 commented 5 years ago

Any remarks on why this might be a bad idea? I'd appreciate any feedback.

No 😄 if it works for you, then I think it's a good idea.

sabbadino commented 4 years ago

Is there some configuration setting so that the topic is created even if no subscriber exists yet ?

mookid8000 commented 4 years ago

@sabbadino no – but after having thought about this for quite a long time, I am beginning to lean towards making it so that topics are created whenever 1) a publisher publishes to it, or 2) a subscriber subscribes to it, whichever comes first.

Via configuration it could then be made possible to configure publishers to skip the creation, if that is desired.

The reasoning behind this design would be that it makes it easy to implement publishing and subscribing in a way that does not rely on MessagingEntityNotFoundExceptions too much (~1 caught & swallowed exception per topic creation), and it makes it visible which topics actually exist.

If it's a problem that too many topics are created, I would question the design that led to so many topics. After all, what is the purpose of a topic if it's not meant to be created? I can't think of any good reasons why anyone would want "invisible" topics to exist.

If anyone has any objections to this, please say so pretty soon – otherwise it will make it into a v7 prerelease version soon..... 🙂

sabbadino commented 4 years ago

+1 :)