Skip to content

Commit f3c5716

Browse files
Add Azure Functions App + Service Bus Sample (#61)
* Add Azure Functions App + Service Bus Sample * Update README.md with new sample
1 parent 48a95eb commit f3c5716

73 files changed

Lines changed: 8016 additions & 15 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ This repository contains comprehensive sample projects demonstrating how to deve
2929
| [Function App and Storage](./samples/function-app-storage-http/dotnet/README.md) | Azure Functions App using Blob, Queue, and Table Storage |
3030
| [Function App and Front Door](./samples/function-app-front-door/python/README.md) | Azure Functions App exposed via Front Door |
3131
| [Function App and Managed Identities](./samples/function-app-managed-identity/python/README.md) | Azure Function App using Managed Identities |
32+
| [Function App and Service Bus](./samples/function-app-service-bus/dotnet/README.md) | Azure Function App using Service Bus |
3233
| [Web App and CosmosDB for MongoDB API ](./samples/web-app-cosmosdb-mongodb-api/python/README.md) | Azure Web App using CosmosDB for MongoDB API |
3334
| [Web App and CosmosDB for NoSQL API ](./samples/web-app-cosmosdb-nosql-api/python/README.md) | Azure Web App using CosmosDB for NoSQL API |
3435
| [Web App and Managed Identities](./samples/web-app-managed-identity/python/README.md) | Azure Web App using Managed Identities |

samples/function-app-managed-identity/python/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ The LocalStack emulator emulates the following services, which are necessary at
4545

4646
- [Azure Subscription](https://azure.microsoft.com/free/)
4747
- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
48+
- [Azure Functions Core Tools](https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local)
4849
- [Python](https://www.python.org/downloads/)
4950
- [Flask](https://flask.palletsprojects.com/)
50-
- [pyodbc](https://github.com/mkleehammer/pyodbc)
5151
- [Bicep extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep), if you plan to install the sample via Bicep.
5252
- [Terraform](https://developer.hashicorp.com/terraform/downloads), if you plan to install the sample via Terraform.
5353

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Azure Functions App with Service Bus Messaging
2+
3+
This sample demonstrates how to deploy an [Azure Functions App](https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview) on an [Azure App Service Plan](https://learn.microsoft.com/en-us/azure/app-service/overview-hosting-plans) that exchanges messages through queues in a [Service Bus](https://learn.microsoft.com/en-us/azure/service-bus/service-bus-overview) namespace. The function app authenticates to Azure resources using a [user-assigned managed identity](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) and connects to the Service Bus namespace via an [Azure Private Endpoint](https://learn.microsoft.com/azure/private-link/private-endpoint-overview) for secure, private network communication.
4+
5+
## Architecture
6+
7+
The following diagram illustrates the architecture of the solution:
8+
9+
![Architecture Diagram](./images/architecture.png)
10+
11+
The function app is composed of the following functions:
12+
13+
- **GreetingRequester**: Timer-triggered function that periodically sends a request message containing a randomly generated name to the `input` queue.
14+
- **GreetingHandler**: Uses the [Azure Service Bus trigger](https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus-trigger) to listen for incoming messages on the `input` queue. When a message arrives, it extracts the name, composes a greeting, and sends the result to the `output` queue using the [Azure Service Bus output binding](https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus-output).
15+
- **GreetingConsumer**: Timer-triggered function that periodically polls the `output` queue, retrieves greeting response messages, and logs them for monitoring.
16+
- **GetGreetings**: HTTP-triggered function that returns the most recent greetings stored in an in-memory circular buffer. Greetings are returned in reverse chronological order (newest first), providing a quick way to verify the message pipeline is working.
17+
18+
The solution is composed of the following Azure resources:
19+
20+
1. [Azure Resource Group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-cli): A logical container scoping all resources in this sample.
21+
2. [Azure Virtual Network](https://learn.microsoft.com/azure/virtual-network/virtual-networks-overview): Hosts two subnets:
22+
- *app-subnet*: Dedicated to [regional VNet integration](https://learn.microsoft.com/azure/azure-functions/functions-networking-options?tabs=azure-portal#outbound-networking-features) with the Function App.
23+
- *pe-subnet*: Used for hosting Azure Private Endpoints.
24+
3. [Azure Private DNS Zones](https://learn.microsoft.com/azure/dns/private-dns-privatednszone): Provide internal DNS resolution so that resources within the virtual network can reach Private Endpoints by hostname rather than public addresses. There is a separate Azure Private DNS Zone for the following resource types:
25+
- Azure Service Bus namespace
26+
- Azure Blob Storage
27+
- Azure Queue Storage
28+
- Azure Table Storage
29+
4. [Azure Private Endpoints](https://learn.microsoft.com/azure/private-link/private-endpoint-overview): Provide secure, private network connectivity to Azure resources by exposing them through private IP addresses within the virtual network, eliminating the need for traffic to traverse the public internet. There is a separate Azure Private Endpoint for the following resources:
30+
- Azure Service Bus namespace
31+
- Azure Blob Storage
32+
- Azure Queue Storage
33+
- Azure Table Storage
34+
5. [Azure NAT Gateway](https://learn.microsoft.com/azure/nat-gateway/nat-overview): Provides deterministic outbound connectivity and a stable public IP address for the Function App's outbound traffic. Included for architectural completeness; the sample app itself does not call any external services.
35+
6. [Azure Network Security Group](https://learn.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview): Enforces inbound and outbound traffic rules across the virtual network's subnets.
36+
7. [Azure Log Analytics Workspace](https://learn.microsoft.com/azure/azure-monitor/logs/log-analytics-overview): Centralizes diagnostic logs and metrics from all resources in the solution, enabling unified querying and analysis across the entire deployment.
37+
8. [Azure App Service Plan](https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview-hosting-plans): Defines the underlying compute tier and scaling behavior for the function app.
38+
9. [Azure Functions App](https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview): Hosts the sample function app.
39+
10. [Azure Application Insights](https://learn.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview): Provides application performance monitoring (APM), collecting and analyzing requests, traces, and metrics generated by the function app to surface performance bottlenecks and failures.
40+
11. [Azure Service Bus](https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-overview): A fully managed enterprise message broker. This namespace hosts the `input` and `output` queues used by the function app to exchange messages asynchronously.
41+
12. [Azure Storage Account](https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview): Provides durable storage used internally by the Azure Functions runtime for state management, including distributed locks, checkpoints, and timer trigger coordination.
42+
13. [User-Assigned Managed Identity](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview): This identity is assigned the necessary RBAC roles and is used by the function app to authenticate securely—without storing credentials—to the following Azure resources:
43+
- Azure Service Bus namespace
44+
- Azure Storage
45+
- Azure Application Insights
46+
47+
## Prerequisites
48+
49+
- [Azure Subscription](https://azure.microsoft.com/free/)
50+
- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
51+
- [Azure Functions Core Tools](https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local) is required to build, run, and deploy the Azure Functions app locally
52+
- [.NET SDK](https://dotnet.microsoft.com/en-us/download) is required to compile and run the C# Azure Functions project
53+
- [Bicep extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep), if you plan to install the sample via Bicep.
54+
- [Terraform](https://developer.hashicorp.com/terraform/downloads), if you plan to install the sample via Terraform.
55+
56+
## Deployment
57+
58+
Set up the Azure emulator using the LocalStack for Azure Docker image. Before starting, ensure you have a valid `LOCALSTACK_AUTH_TOKEN` to access the Azure emulator. Refer to the [Auth Token guide](https://docs.localstack.cloud/getting-started/auth-token/?__hstc=108988063.8aad2b1a7229945859f4d9b9bb71e05d.1743148429561.1758793541854.1758810151462.32&__hssc=108988063.3.1758810151462&__hsfp=3945774529) to obtain your Auth Token and set it in the `LOCALSTACK_AUTH_TOKEN` environment variable. The Azure Docker image is available on the [LocalStack Docker Hub](https://hub.docker.com/r/localstack/localstack-azure-alpha). To pull the image, execute:
59+
60+
```bash
61+
docker pull localstack/localstack-azure-alpha
62+
```
63+
64+
Start the LocalStack Azure emulator by running:
65+
66+
```bash
67+
export LOCALSTACK_AUTH_TOKEN=<your_auth_token>
68+
IMAGE_NAME=localstack/localstack-azure-alpha localstack start
69+
```
70+
71+
Deploy the application to LocalStack for Azure using one of these methods:
72+
73+
- [Azure CLI Deployment](./scripts/README.md)
74+
- [Bicep Deployment](./bicep/README.md)
75+
- [Terraform Deployment](./terraform/README.md)
76+
77+
All deployment methods have been fully tested against Azure and the LocalStack for Azure local emulator.
78+
79+
> **Note**
80+
> When you deploy the application to LocalStack for Azure for the first time, the initialization process involves downloading and building Docker images. This is a one-time operation—subsequent deployments will be significantly faster. Depending on your internet connection and system resources, this initial setup may take several minutes.
81+
82+
## Test
83+
84+
Once the resources and function app have been deployed, you can use the [call-http-trigger.sh](./scripts/call-http-trigger.sh) Bash script to invoke the **GetGreetings** HTTP-triggered function. This function returns the most recent greetings stored in the in-memory circular buffer, allowing you to verify that the entire message pipeline is working end to end.
85+
86+
You can also inspect the function app's runtime behavior by viewing the logs of its Docker container. Run `docker logs ls-local-func-test-xxxxxx` (replacing `xxxxxx` with the actual container suffix) to see output similar to the following:
87+
88+
```bash
89+
[2026-03-17T13:11:30.000Z] Executing 'Functions.GreetingRequester' (Reason='Timer fired at 2026-03-17T13:11:30.0002087+00:00', Id=1677eef3-d54a-434a-b21c-0bb1606ebedc)
90+
[2026-03-17T13:11:30.001Z] [GreetingRequester] Timer trigger function started.
91+
[2026-03-17T13:11:30.001Z] [GreetingRequester] Creating Service Bus client for sending messages...
92+
[2026-03-17T13:11:30.001Z] [GreetingRequester] Creating sender for input queue 'input'
93+
[2026-03-17T13:11:30.001Z] [GreetingRequester] Sending message to input queue 'input'...
94+
[2026-03-17T13:11:30.219Z] [GreetingRequester] Successfully sent message to input queue 'input' with name: Jane
95+
[2026-03-17T13:11:30.219Z] [GreetingRequester] Function Ran. Next timer schedule = (null)
96+
[2026-03-17T13:11:30.219Z] Executed 'Functions.GreetingRequester' (Succeeded, Id=1677eef3-d54a-434a-b21c-0bb1606ebedc, Duration=218ms)
97+
[2026-03-17T13:11:30.298Z] Executing 'Functions.GreetingHandler' (Reason='(null)', Id=5ec3e867-0073-44d4-8dc8-869e0ce95401)
98+
[2026-03-17T13:11:30.298Z] Trigger Details: MessageId: c5a1b026-b435-4f62-b273-de9f6e2224a1, SequenceNumber: 1, DeliveryCount: 1, EnqueuedTimeUtc: 2026-03-17T13:11:30.2170000+00:00, LockedUntilUtc: 2026-03-17T13:12:30.2170000+00:00, SessionId: (null)
99+
[2026-03-17T13:11:30.299Z] [GreetingHandler] Message ID: c5a1b026-b435-4f62-b273-de9f6e2224a1
100+
[2026-03-17T13:11:30.299Z] [GreetingHandler] Message Body: {"name":"Jane"}
101+
[2026-03-17T13:11:30.299Z] [GreetingHandler] Message Content-Type: application/json
102+
[2026-03-17T13:11:30.299Z] [GreetingHandler] Processing request for name: Jane
103+
[2026-03-17T13:11:30.299Z] Start processing HTTP request POST http://127.0.0.1:43127/Settlement/Complete
104+
[2026-03-17T13:11:30.299Z] Sending HTTP request POST http://127.0.0.1:43127/Settlement/Complete
105+
[2026-03-17T13:11:30.302Z] Received HTTP response headers after 2.609ms - 200
106+
[2026-03-17T13:11:30.302Z] End processing HTTP request after 2.6465ms - 200
107+
[2026-03-17T13:11:30.302Z] [GreetingHandler] Processed message [c5a1b026-b435-4f62-b273-de9f6e2224a1] successfully: Hi Jane, great to see you!
108+
[2026-03-17T13:11:30.303Z] Executed 'Functions.GreetingHandler' (Succeeded, Id=5ec3e867-0073-44d4-8dc8-869e0ce95401, Duration=4ms)
109+
[2026-03-17T13:11:34.375Z] [GreetingConsumer] Function Ran. Next timer schedule = (null)
110+
[2026-03-17T13:11:34.375Z] Executed 'Functions.GreetingConsumer' (Succeeded, Id=32dbc94a-4ff7-4315-9de4-ea36593589fc, Duration=10427ms)
111+
[2026-03-17T13:11:34.380Z] Executing 'Functions.GreetingConsumer' (Reason='Timer fired at 2026-03-17T13:11:34.3806261+00:00', Id=af37440c-360b-4114-97ea-bf88f1843bcf)
112+
[2026-03-17T13:11:34.381Z] [GreetingConsumer] Timer trigger function started.
113+
[2026-03-17T13:11:34.381Z] [GreetingConsumer] Creating Service Bus client for receiving messages...
114+
[2026-03-17T13:11:34.381Z] [GreetingConsumer] Starting to receive messages from output queue 'output'
115+
[2026-03-17T13:11:34.799Z] [GreetingConsumer] Successfully received and deserialized message from output queue. Date: 2026-03-17T13:06:30, Text: Hi Jane, great to see you!
116+
[2026-03-17T13:11:39.802Z] [GreetingConsumer] No more messages available in output queue 'output'
117+
```
118+
119+
## References
120+
121+
- [Azure Functions Apps Documentation](https://learn.microsoft.com/en-us/azure/app-service/)
122+
- [Azure Service Bus](https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-overview)
123+
- [LocalStack for Azure](https://azure.localstack.cloud/)

0 commit comments

Comments
 (0)