Search code examples
azureazureservicebusazure-servicebus-queues

Identify consumer of Azure Service Bus queue


I'm taking over responsibility for an Azure Service Bus deployment. Documentation is incomplete in that there are undocumented Queues and Topic Subscriptions present.

What information can Azure provide me about the function that is consuming messages sent to a queue/topic subscription? I'd like ultimately to be able to locate the source code which is processing the messages.

e.g. a class library name, class name or even just a namespace of the function that receives the messages. Something. Anything.

Or am I asking the wrong question?


Solution

  • Seems like an oversight on Azure that all information about Service Bus ends at the definition of the "inbox" and offers nothing about the functions that deal with received messages.

    Problem is, the whole idea of using a Service Bus is to decouple (parts of) applications, so the sender does not have a tight relationship with the receiver of the message. From your story it seems your consumers are probably Azure Functions but in other situations receiver might be running on-premises or in an other cloud environment like AWS or Google Cloud. The Azure Service Bus does simply not know what kind of hosting environment is consuming the messages. Tools like Application Insights can generate this kind of information but only if enabled on the consuming side.

    What information can Azure provide me about the function that is consuming messages sent to a queue/topic subscription? I'd like ultimately to be able to locate the source code which is processing the messages.

    e.g. a class library name, class name or even just a namespace of the function that receives the messages. Something. Anything.

    If the producing/consuming applications have an Application Insights integration the Application Map might reveal this information.

    Enabling Azure Functions to consume Service Bus messages is all based on configuration so you could scan your code repositories based topic names but there are plenty of other locations where this configuration can be stored like Azure Function Application Settings, Azure Key Vault, Azure App Configuration etc.

    Even a statement "There are no consumers on this queue/subscription" would be a help.

    The closest you can get is see whether there are active messages waiting to be delivered:

    enter image description here

    If there is no (active) consuming subscription while messages are pushed I would expect an increasing value of the Active Message Count metric. But do mind the Message Time to Live for the specific topic.

    Or am I asking the wrong question?

    It is a valid question and I definitely feel your pain but there is no satisfying answer to your question. For loosly coupled systems you need documentation, distributed tracing and possibly infrastructure as code to tackle issues like this.

    Getting a list of Azure Functions and their bindings

    In your comments you mention that it would help to get a list of functions and their bindings. I do know how to do that using the management SDK:

    using Azure.Identity;
    using Azure.ResourceManager;
    using Azure.ResourceManager.AppService;
    
    internal class Program
    {
        private static async Task Main(string[] args)
        {
            var client = new ArmClient(new DefaultAzureCredential(new DefaultAzureCredentialOptions()
            {
                ExcludeVisualStudioCredential = true,
                ExcludeVisualStudioCodeCredential = true
            }));
    
            var azureFunctions = new List<SiteFunctionResource>();
    
            foreach (var subscription in client.GetSubscriptions())
            {
                var resourceGroups = subscription.GetResourceGroups();
                await foreach (var resourceGroup in resourceGroups.GetAllAsync())
                {
                    var websites = resourceGroup.GetWebSites();
                    azureFunctions.AddRange(
                        websites
                            .Where(ws => ws.Data.Kind.Contains("functionapp", StringComparison.InvariantCultureIgnoreCase))
                            .SelectMany(ws => ws.GetSiteFunctions().ToList())
                        );
                }
            }
    
            foreach (var azureFunction in azureFunctions)
            {
                var bindings = azureFunction.Data.Config.ToObjectFromJson<Config>().bindings;
                Console.WriteLine(azureFunction.Id);
                Console.WriteLine("bindings:");
                foreach (var binding in bindings)
                {
                    Console.WriteLine($"\t{binding.name}: {binding.type}");
                }
                Console.WriteLine("-----------------------------------");
            }
    
            Console.ReadLine();
        }
    
        public class Binding
        {
            public string type { get; set; }
            public string route { get; set; }
            public List<string> methods { get; set; }
            public string authLevel { get; set; }
            public string name { get; set; }
        }
    
        public class Config
        {
            public List<Binding> bindings { get; set; }
        }
    }
    

    It needs the following NuGet packages:

    <PackageReference Include="Azure.Identity" Version="1.7.0-beta.1" />
    <PackageReference Include="Azure.ResourceManager" Version="1.3.0" />
    <PackageReference Include="Azure.ResourceManager.AppService" Version="1.0.0-beta.3" />
    

    Sample output:

    enter image description here