Azure Cosmos DB has a nifty change feed feature that tracks create and update events on documents in a collection. Applications, including serverless apps built with Azure Functions, can read events from the change feed and listen to new events on the change feed in real-time.
Azure SignalR Service is a managed service that allows applications to broadcast real-time messages to many connected clients over WebSockets and other supported transports.
September 24, 2018 - Azure SignalR Service is now generally available!
In this article, we'll look at how we can use Azure Functions and SignalR Service to broadcast real-time document changes in Azure Cosmos DB to clients over WebSockets.
Overview
Here's how all the pieces fit together.
- A document is created or updated in Azure Cosmos DB.
- The change or update event is automatically logged in the Azure Cosmos DB change feed.
- Using the Azure Cosmos DB trigger, an Azure Function is invoked when the event appears in the change feed.
- Using the SignalR Service output binding, the function outputs a message to SignalR Service.
- SignalR Service sends the message to all connected clients over WebSockets.
The SignalR client SDK is available in JavaScript and .NET Standard. There's also a Java client coming soon. We'll use a simple Vue.js app in a browser for this project. Using the .NET Standard SDK, we can also build desktop apps with .NET Framework and .NET Core or mobile apps with Xamarin to receive messages from SignalR Service.
Connecting Azure Cosmos DB change feed to SignalR Service with Azure Functions
We'll first look at how to implement our Azure Functions using JavaScript, then we'll do the same with C#. Java and Python support in Azure Functions are coming in the future.
The example we'll use is an airline flight pricing database. Each flight is a document in a Azure Cosmos DB collection, and any changes in the data will be reflected in the application in real-time.
JavaScript
The complete solution can be found here. The main function we'll look at is OnDocumentsChanged.
In function.json
, we define two bindings:
- Azure Cosmos DB trigger - when a change is detected in the
flights
collection, the function is executed, passing in the updated document(s) in an argument named updatedFlights
. - SignalR Service output binding - used by the function to output messages to a SignalR Service hub named
flights
.
{
"disabled": false,
"bindings": [
{
"type": "cosmosDBTrigger",
"name": "updatedFlights",
"direction": "in",
"databaseName": "demo",
"collectionName": "flights",
"feedPollDelay": 1000
},
{
"type": "signalR",
"name": "signalRMessages",
"hubName": "flights",
"direction": "out"
}
]
}
To use the Azure Cosmos DB and SignalR Service bindings, we need to install them using the Functions Core Tools CLI:
func extensions install -p Microsoft.Azure.WebJobs.Extensions.CosmosDB -v 3.0.1
func extensions install -p Microsoft.Azure.WebJobs.Extensions.SignalRService -v 1.0.0-preview1-10002
Check the extensions (Azure Cosmos DB, SignalR Service) for the latest versions of these packages. Currently (September 2018), the SignalR Service bindings are in public preview, but the service itself is generally available.
Also ensure that these app settings are configured with the relevant connection strings: AzureWebJobsCosmosDBConnectionString
and AzureSignalRConnectionString
.
The function itself is very simple. We are simply mapping the array of updated documents into an array of SignalR Service message objects. Our message object instructs SignalR Service to invoke the flightUpdated
method on each client with the Azure Cosmos DB document as the argument. A SignalR Service message contains two properties:
target
- The name of the method to invoke on each client arguments
- The arguments to pass to the method
module.exports = function (context, updatedFlights) {
context.bindings.signalRMessages =
updatedFlights.map(flight => ({
target: 'flightUpdated',
arguments: [flight]
}));;
context.done();
};
Skip to the next section to see how to implement the client-side JavaScript.
C#
Take a look at this solution to implement the same thing in C#.
To use the Azure Cosmos DB and SignalR Service bindings, we need to install them via NuGet:
dotnet add package Microsoft.Azure.WebJobs.Extensions.CosmosDB --version 3.0.1
dotnet add package Microsoft.Azure.WebJobs.Extensions.SignalRService --version 1.0.0-preview1-10002
Check the extensions NuGet packages (Azure Cosmos DB, SignalR Service) for the latest versions. Currently (September 2018), the SignalR Service bindings are in public preview, but the service itself is generally available.
Also ensure that these app settings are configured with each service's connection string: AzureWebJobsCosmosDBConnectionString
and AzureSignalRConnectionString
.
The function that we want to look at is OnDocumentsChanged:
[FunctionName("OnDocumentsChanged")]
public static async Task Run(
[CosmosDBTrigger("demo", "flights", ConnectionStringSetting = "AzureWebJobsCosmosDBConnectionString")]
IEnumerable<object> updatedFlights,
[SignalR(HubName = "flights")] IAsyncCollector<SignalRMessage> signalRMessages,
ILogger log)
{
foreach(var flight in updatedFlights)
{
await signalRMessages.AddAsync(new SignalRMessage
{
Target = "flightUpdated",
Arguments = new[] { flight }
});
}
}
The CosmosDBTrigger
attribute is listening to changes in a collection named flights
in a database named demo
. When a change occurs, the function is triggered and the list of updated document(s) are available in the updatedFlights
parameter.
The function uses the SignalR
output binding to output messages to a SignalR Service hub named flights
. We'll invoke a method named flightUpdated
on each connected client, passing the updated document as the argument. A SignalR Service message contains two properties:
Target
- The name of the method to invoke on each client Arguments
- The arguments to pass to the method
Receiving real-time updates in a browser
Both the JavaScript and C# implementations invoke a flightUpdated
method on each client. In the client-side JavaScript, add an event listener for flightUpdated
:
connection.on('flightUpdated', flightUpdated)
function flightUpdated(updatedFlight) {
}
To see the body of flightUpdated
and the rest of the single page app, take a look at index.html.
And that's all we need to do to broadcast changes in Azure Cosmos DB to clients connected to SignalR Service!
Resources
The source code is on GitHub.
Azure SignalR Service is now generally available. Learn more by reading the docs and try it today!
Check out this episode of On .NET, where we demo this application [19:35].