Page Type | Languages | Key Services | Tools |
---|---|---|---|
Sample | JavaScript (Node.js, React.js) Python PowerShell |
Azure SignalR Azure Functions Azure Container Apps Azure Container Registry |
Docker GitHub Actions |
This sample codebase demonstrates how to use Azure SignalR to add real-time functionality to a serverless containerized web application hosted in Azure Container Apps written in React.js with a Node.js backend proxy server. This sample uses serverless Azure Functions for processing requests made by the application.
The motivation behind this guide is the observed lack of readily available open-source codebase examples using these technologies together.
This sample builds on top of existing approaches documented by Microsoft, namely:
- Serverless development and configuration with Azure SignalR
- SignalR quickstart for JavaScript
- ASP.NET Core SignalR JavaScript client
SignalR is a solution that introduces real-time functionality to a webpage, addressing scenarios such as a user needing to refresh a webpage to fetch new data, or an application performing long-polling for data to become available.
Although the scenario presented in this codebase is simple and contrived, it should be viewed as a foundation for modification and expansion into more complex applications.
- An Azure Subscription - for hosting cloud infrastructure
- Az CLI - for deploying Azure infrastructure as code
- Azure Functions Core Tools and Azurite - for testing Functions locally
- Python - for Python development
- Node.js - for Node.js development
- (Optional) A GitHub Account - for deploying code via GitHub Actions
- Register a new application
- Create a new client secret - you will use this if you choose to automate the deployment of the application using GitHub Actions
- Add the desired resource names in
devops/config/variables.json
- Either:
- Update the branch trigger in the
.github/workflows/web-infra.yml
file to trigger the GitHub Action, or - Run the script
devops/scripts/web/aca.ps1
locally.
- Update the branch trigger in the
- This will create the Container App and all of the related components including a Container Registry, Container Instance, Managed Identity, Log Analytics Workspace, and Container App Environment.
- Add the desired resource names in
devops/config/variables.json
- Either:
- Update the branch trigger in the
.github/workflows/integration-infra.yml
file to trigger the GitHub Action, or - Run the scripts
devops/scripts/integration/function.ps1
anddevops/scripts/integration/signalr.ps1
locally.
- Update the branch trigger in the
- This will create the Function App and SignalR instances, in addition to all of the related components including a Storage Account, App Insights, and an App Service Plan.
- To deploy to Azure using GitHub Actions, a handful of credentials are required for connection and configuration. In this example, they will be set as Actions Secrets. For each of the below secrets, the secret name and steps on how to populate the secret is provided.
-
AZURE_SP_CREDENTIALS
:- A JSON object that looks like the following will need to be populated with 4 values:
{ "clientId": "<GUID>", "clientSecret": "<STRING>", "subscriptionId": "<GUID>", "tenantId": "<GUID>" }
- You can find more details on creating this secret here.
- For clientId, run:
az ad sp list --display-name <service principal name> --query '[].[appId][]' --out tsv
- For tenantId, run:
az ad sp show --id <clientID> --query 'appOwnerOrganizationId' --out tsv
- For subscriptionId, run:
az account show --query id --output tsv
- For clientSecret: This is the client secret created alongside the App Registration above
-
SIGNALR_CONNECTION_STRING
: In the Azure Portal, navigate to the SignalR service that was created above, and go to 'Connection strings' blade.
- Note: This section will discuss deployment of the codebase via GitHub Actions. If you choose not to deploy via GitHub Actions, you may opt to manually deploy the code by following the automated tasks or with another CI/CD tool - the steps will be the same.
-
Deploy the Negotiate and Broadcast functions first by updating the branch trigger in the
.github/workflows/integration-cicd.yml
file to trigger the GitHub Action.- This will deploy two functions to the above deployed Function App. The functions in this codebase are written in Python, and are described in more detail in the below section.
-
Then, deploy the web application by updating the branch trigger in the
.github/workflows/web-cicd.yml
file to trigger the GitHub Action.- This will build a Docker image, push it to the Container Registry, and update the Container App.
A diagram visually describing the flow of code from local development to GitHub to Azure, and the way the components communicate in Azure.
- To connect to SignalR, a valid access token is required. An HTTP-triggered "Negotiate" function is called by the client application to generate the required connection token. The negotiate function is described more here. When the web application is launched, the negotiate function is called immediately.
- To send a message, a "Broadcast" function is required, which uses the connection information fetched in Step 1, and binds a trigger to SignalR. The
@microsoft/signalr
npm package is used to establish the connection.- This is where logic/backend processing will take place. The broadcast function in this codebase takes a string as input, generates a salt and uses it to create a cryptographic hash of the input string (this is a safeguarding technique used in authentication data stores).
- * In this example the Broadcast Function uses an HTTP trigger, but the function can be set up to be triggered by any number of bindings - see all supported bindings here. In a real-world application, using another type of binding to trigger an event may be more practical.
- Clients (e.g., the application in this repository) can connect and listen to SignalR for new messages. In real time, when SignalR receives a new message, the client will consume it over a WebSocket.
- There are many practical use cases for enabling real-time functionality to a webpage, some of which include instant messaging, real-time dashboards, gaming, and sports.