Search

Inter-App Messaging with Azure Functions, Azure Service Bus, and CosmosDB

With the rise of cloud computing, microservices and serverless are the latest frameworks for problem-solving. With microservices, you can build truly scalable and distributed systems. Using serverless solutions, your application will scale up and down automatically, depending on usage, without needing to worry about infrastructure.

The new challenge that microservices bring is allowing separate microservices to function as a single system. To make this happen, you need some kind of messaging solution. This article will demonstrate how to build serverless Azure Functions that use Azure Service Bus as a messaging solution.

Building our first Function App

First, we are going to build an Azure Function. An Azure Function is really what the name implies: a function. The function can be written in several languages, such as F#, Java, and JavaScript, but for this example, we will be using C#.

The function can be triggered from various sources, such as by HTTP requests, on a timer, when something is added to a Service Bus queue, when a blob is written to a storage account, or when something changes in a Cosmos DB instance, for example.

There are two ways to build Azure Functions — either from the Azure Portal or in Visual Studio.

When using Visual Studio, you can’t quickly edit Functions in the portal, but you can write more complex functions (and get the benefits of IntelliSense and other Visual Studio coding features). You can also use Azure DevOps for source control and CI/CD.

We’re going to use the Azure Portal. In Azure Portal, you will find your Function Apps (which is a container for your Functions). Now you will simply create a new one. Think of a unique name for your app, pick a subscription and resource group, and disable Application Insights.

When the Function App has been created, you can start adding an actual Function. Click the plus sign next to Functions and select “In-portal.” Then click Continue at the bottom of the screen. On the next screen, click Webhook + API and then click Create.

You’ll be presented with a sample Function that checks your HTTP query and body for a “name” parameter, and then echoes “Hello, {name}” to the caller. The interesting thing to notice here is the HttpRequest input parameter. This is called a “binding” and represents what triggered your Function. (More on that later.) You can test the function by clicking Run at the top.

The goal of this article is to send this piece of data, trivial as it may be, to another Function using a Service Bus.

Adding Service Bus

Next, we’re going to create a Service Bus, which is quite simple. All you need to do is find Service Bus in the portal and add a new one. Using the Basic pricing tier is fine for this example.

Wait for the service bus to be created, and then add a queue. Name it “names.” (This is fairly straightforward just keep all the default settings.)

Just like a Function can bind trigger data to an input parameter, it can bind output parameters to certain actions. In this case, we want to output something to a Service Bus.

Go into your Function and find the “Integrate” menu. This is where your bindings are located. Notice the HTTP trigger, which binds your trigger to the HttpRequest. Here, add a new Output and choose “Azure Service Bus.” (At this point, you may have to install an extension to enable Service Bus in your Functions.) Now, pick “Service Bus Queue” as Message type and change the queue name to “names.”

You will need to create a new Service Bus connection, so click on new, select your Service Bus, and hit “Select.”

Save your new Output and return to the Function’s code.

Now we have a bit of a problem. We bound the Service Bus output to an out parameter, but that’s not supported in async methods. So we need to change the method signature to match:

				
					public static IActionResult Run(HttpRequest req, 
  ILogger log, out string outputSbMsg)
				
			

Make sure you actually remove the awaited method call:

				
					string requestBody = new StreamReader(req.Body).ReadToEnd();
				
			

Last, but not least, assign a value to the new parameter right before the return statement:

				
					outputSbMsg = name;
return name != null
    // …
				
			

Now save and run your code. If all went well, you should have a new message in your queue.

Another App

Now, another app is going to take care of handling the name. Create a new Function App as in the previous example. (This way, we keep our input service separated from the handling service, which allows us to develop and deploy them separately.)

Once the app is created, add a new Function. This time, under “More Templates,” pick “Azure Service Bus Queue trigger.” You’ll have to install the extension for this app as well. Create a connection and change the queue name to “names.”

The handling itself will be extremely simple. We’re just going to put the name in a Cosmos DB database so we can query it later.

Adding Cosmos DB

Creating a Cosmos DB database instance is simple as well. Find Azure Cosmos DB in the portal and add a new one. (Make sure you keep the default “Core (SQL)” API selected, as it’s the only one supported for bindings in Functions.)

Wait for creation to complete and head back to your Service Bus-triggered function.

Go to “Integrate” and add a new output binding. We’re going to use the return value, so select the checkbox. Create a new Cosmos DB connection. (This works much like the Service Bus connection.) Pick names for your database and collection, and select the “If true, creates the Azure Cosmos DB Database and collection” checkbox. (Don’t forget to save.)

In a few cases I’ve encountered what appears to be a bug related to the Cosmos DB output binding. In your Function App, go to Platform Features > App Service Editor. You may find a file there, app_offline.htm, that is created to take your app offline while the binding is created. If it’s there when it’s no longer needed, you can remove it by right-clicking the file and selecting “Delete.”

We’ll also have to make some code changes. You’ll need to return an object that will be stored in the database, then add a return statement that returns some object.

				
					using System;
using System.Threading.Tasks;

public static object Run(string myQueueItem, ILogger log)
{
    log.LogInformation($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
    return new
    {
        Name = myQueueItem
    };
}
				
			

Run your first function again and provide a name. If you did everything correctly, you should now have a document in your database, which you can view using the Data Explorer in your Cosmos DB instance.

Getting the data

Lastly, we’re going to create a separate Function to retrieve the data from the database.

In the Function App that has the Cosmos DB output, create a new Webhook + API Function. We’re going to use the Microsoft.Azure.DocumentDB.Core package to connect to our database.

Unfortunately, it is not possible to create a client using a connection string, so you’ll have to look up your database’s URI and primary key and copy them in the code. They can be found under “Keys” in your Cosmos DB in Azure. You can also put them in your app’s configuration and retrieve them as an environment variable. I’ve added the connectionString as an example. The code should be as follows:

				
					#r "Microsoft.Azure.DocumentDB.Core"

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Documents.Client;

public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    var connectionString = Environment.GetEnvironmentVariable("contentlabcosmosdb_DOCUMENTDB");
    var client = new DocumentClient(new Uri("https://[your account].documents.azure.com:443"), "tGtblssO4[your code...]");
    var docs = client.CreateDocumentQuery<dynamic>(UriFactory.CreateDocumentCollectionUri("namesdb", "Names")).ToList();

    return new OkObjectResult(docs);
}
				
			

If you did everything correctly, you should be able to call the API and get a list of names. Go back to the first app and add a name, then see if it is added.

Conclusion

Using Azure Functions in the Portal, we were able to create two separate microservices with their own Functions and have them communicate through an Azure Service Bus, which only took a couple of minutes. Function bindings are a powerful tool to quickly move data between applications. While the example in this article is simple, the same principles apply when building larger Functions and Function Apps. As an example, one app can be sales-focused, while the other keeps track of stock. Or one app can send a document to another app for quick processing, and the first app puts it in a queue. For a deep dive in scalable app design, I would recommend reading Designing Data-Intensive Applications.

If you’re interested in developing expert technical content that performs, let’s have a conversation today.

Facebook
Twitter
LinkedIn
Reddit
Email

POST INFORMATION

If you work in a tech space and aren’t sure if we cover you, hit the button below to get in touch with us. Tell us a little about your content goals or your project, and we’ll reach back within 2 business days. 

Share via
Copy link
Powered by Social Snap