Skip to content

Commit f3db540

Browse files
Merge pull request #188156 from danielgerlag/jobrouter/storage-queue
JobRouter event subscription quick-start
2 parents 9bfdc13 + 7cb6382 commit f3db540

File tree

2 files changed

+193
-128
lines changed

2 files changed

+193
-128
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3+
"contentVersion": "1.0.0.0",
4+
"parameters": {
5+
"storageName": {
6+
"type": "string",
7+
"defaultValue": "[concat('storage', uniqueString(resourceGroup().id))]",
8+
"metadata": {
9+
"description": "Provide a unique name for the Storage account."
10+
}
11+
},
12+
"eventSubName": {
13+
"type": "string",
14+
"defaultValue": "routerSubscription",
15+
"metadata": {
16+
"description": "Provide a name for the Event Grid subscription."
17+
}
18+
},
19+
"azureCommunicationServicesResourceName": {
20+
"type": "String",
21+
"metadata": {
22+
"description": "Name of your ACS resource."
23+
}
24+
},
25+
"systemTopicName": {
26+
"type": "String",
27+
"metadata": {
28+
"description": "Name of the system topic. If you have an existing topic, find it under 'Events' in your ACS resource, otherwise specify a unique name"
29+
}
30+
},
31+
"queueName": {
32+
"type": "String",
33+
"defaultValue": "router-events",
34+
"metadata": {
35+
"description": "Provide a name for the queue."
36+
}
37+
}
38+
},
39+
"variables": {
40+
"queueId": "[concat(parameters('storageName'), '/default/', parameters('queueName'))]"
41+
},
42+
"resources": [
43+
44+
{
45+
"type": "Microsoft.Storage/storageAccounts",
46+
"apiVersion": "2019-06-01",
47+
"name": "[parameters('storageName')]",
48+
"location": "[resourceGroup().location]",
49+
"sku": {
50+
"name": "Standard_LRS"
51+
},
52+
"kind": "StorageV2",
53+
"properties": {
54+
"accessTier": "Hot"
55+
}
56+
},
57+
{
58+
"type": "Microsoft.Storage/storageAccounts/queueServices",
59+
"apiVersion": "2021-06-01",
60+
"name": "[concat(parameters('storageName'), '/default')]",
61+
"dependsOn": [
62+
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageName'))]"
63+
],
64+
"properties": {
65+
"cors": {
66+
"corsRules": []
67+
}
68+
}
69+
},
70+
{
71+
"type": "Microsoft.Storage/storageAccounts/queueServices/queues",
72+
"apiVersion": "2021-06-01",
73+
"name": "[variables('queueId')]",
74+
"dependsOn": [
75+
"[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageName'), 'default')]",
76+
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageName'))]"
77+
]
78+
},
79+
{
80+
"type": "Microsoft.EventGrid/systemTopics",
81+
"apiVersion": "2021-06-01-preview",
82+
"name": "[parameters('systemTopicName')]",
83+
"location": "global",
84+
"properties": {
85+
"source": "[resourceId('Microsoft.Communication/CommunicationServices', parameters('azureCommunicationServicesResourceName'))]",
86+
"topicType": "Microsoft.Communication.CommunicationServices"
87+
}
88+
},
89+
{
90+
"type": "Microsoft.EventGrid/systemTopics/eventSubscriptions",
91+
"apiVersion": "2021-06-01-preview",
92+
"name": "[concat(parameters('systemTopicName'), '/', parameters('eventSubName'))]",
93+
"dependsOn": [
94+
"[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageName'), 'default')]",
95+
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageName'))]",
96+
"[resourceId('Microsoft.EventGrid/systemTopics', parameters('systemTopicName'))]"
97+
],
98+
"properties": {
99+
"destination": {
100+
"endpointType": "StorageQueue",
101+
"properties": {
102+
"resourceId": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageName'))]",
103+
"queueName": "[parameters('queueName')]"
104+
}
105+
},
106+
"eventDeliverySchema": "EventGridSchema",
107+
"filter": {
108+
"includedEventTypes": [
109+
"Microsoft.Communication.RouterJobReceived",
110+
"Microsoft.Communication.RouterJobClassified",
111+
"Microsoft.Communication.RouterJobLabelsUpdated",
112+
"Microsoft.Communication.RouterJobClassificationFailed",
113+
"Microsoft.Communication.RouterJobCompleted",
114+
"Microsoft.Communication.RouterJobClosed",
115+
"Microsoft.Communication.RouterJobCancelled",
116+
"Microsoft.Communication.RouterJobExceptionTriggered",
117+
"Microsoft.Communication.RouterJobExceptionCleared",
118+
"Microsoft.Communication.RouterWorkerOfferIssued",
119+
"Microsoft.Communication.RouterWorkerOfferAccepted",
120+
"Microsoft.Communication.RouterWorkerOfferDeclined",
121+
"Microsoft.Communication.RouterWorkerOfferRevoked",
122+
"Microsoft.Communication.RouterWorkerOfferExpired",
123+
"Microsoft.Communication.RouterWorkerRegistered",
124+
"Microsoft.Communication.RouterWorkerDeregistered"
125+
]
126+
}
127+
}
128+
}
129+
],
130+
"outputs": {
131+
}
132+
}

articles/communication-services/how-tos/router-sdk/subscribe-events.md

Lines changed: 61 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ ms.custom: template-how-to
1313

1414
# Subscribe to Job Router events
1515

16-
This guide outlines the steps to subscribe to Job Router events from your Azure Communication Services Event Grid subscription. Receiving events is a critical capability your custom applications will need to perform. The actions Job Router will perform on Jobs you submit happen asynchronously and while the SDK provides endpoints to query the status and state of objects in the system, building a reactive event-driven custom application has significant benefits.
16+
This guide outlines the steps to setup a subscription for Job Router events and how to receive them.
17+
18+
For more details on Event Grid, please see the [Event Grid documentation][event-grid-overview].
1719

1820
[!INCLUDE [Private Preview Disclaimer](../../includes/private-preview-include-section.md)]
1921

@@ -22,169 +24,96 @@ This guide outlines the steps to subscribe to Job Router events from your Azure
2224
- An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
2325
- A deployed Communication Services resource. [Create a Communication Services resource](../../quickstarts/create-communication-resource.md).
2426
- Optional: Complete the quickstart to [get started with Job Router](../../quickstarts/router/get-started-router.md)
25-
- Install the [Azure Resource Manager (ARM) client](https://github.com/projectkudu/ARMClient)
26-
- Review the [GitHub sample project using a customized version of the Event Grid Viewer for Job Router](https://github.com/Azure/communication-preview/tree/master/samples/Job-Router/Event-Grid-Viewer)
2727

2828
## Create an Event Grid subscription
2929

3030
> [!NOTE]
31-
> The following scripts are being executed using PowerShell
32-
33-
**Log into your Azure account**
31+
> Since Job Router is still in preview, the events are not included in the portal UI. You have to use an Azure Resource Manager (ARM) template to create a subscription that references them.
3432
35-
```powershell
36-
armclient azlogin
37-
```
33+
This template deploys an EventGrid subscription on a Storage Queue for Job Router events.
34+
If the storage account, queue or system topic do not exist, they will be created as well.
3835

39-
**Set subscription and resource group name**
40-
```powershell
41-
$env:SUB = 'subscriptions/<insert_subscription_id>'
42-
$env:RG = 'resourcegroups/<insert_resource_group_name>'
43-
```
36+
[![Deploy To Azure](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/deploytoazure.svg?sanitize=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fcommunication-services%2Fhow-tos%2Frouter-sdk%2Fmedia%2Fdeploy-subscription.json)
4437

45-
**List all ACS resources in subscription**
46-
```powershell
47-
armclient get "/$env:SUB/$env:RG/providers/Microsoft.Communication/communicationservices?api-version=2020-08-20"
48-
```
49-
**Output**
38+
### Parameters
5039

51-
:::image type="content" source="media/create-subscription-output.png" alt-text="Output of PowerShell command":::
40+
- **Azure Communication Services Resource Name**: The name of your Azure Communication Services resource. For example, if the endpoint to your resource is https://contoso.communication.azure.net, then set to `contoso`.
41+
- **Storage Name**: The name of your Azure Storage Account. If it does not exist, it will be created.
42+
- **Event Sub Name**: The name of the event subscription to create.
43+
- **System Topic Name**: If you have existing event subscriptions on your ACS resource, find the `System Topic` name in the `Events` tab of your ACS resource. Otherwise, specify a unique name such as the ACS resource name itself.
44+
- **Queue Name**: The name of your Queue within your Storage Account. If it does not exist, it will be created.
5245

53-
As we can see, there is currently only one Azure Communication Services resource under the given subscription and resource group.
46+
### Deployed resources
5447

55-
**Set PowerShell variables**
48+
The following resources are deployed as part of the solution
5649

57-
Set the name of your Azure Communication Services resource. For example, if the endpoint to your resource is `https://contoso.communication.azure.net`, then set `ACS_RESOURCE_NAME` to the prefix of the DNS name; `contoso`.
50+
- **Storage Account**: If the storage account name does not exist.
51+
- **Storage Queue**: If the queue does not exist within the storage account.
52+
- **Event Grid System Topic**: If the topic does not exist.
53+
- **Event Grid Subscription**: A subscription for all Job Router events on the storage queue.
5854

59-
```powershell
60-
$env:ACS_RESOURCE_NAME = "<insert_acs_resource_name>"
61-
$env:ACS_RESOURCE_ARM_ID = "/$env:SUB/$env:RG/providers/Microsoft.Communication/CommunicationServices/$env:ACS_RESOURCE_NAME"
62-
$env:API_VERSION = "?api-version=2020-06-01"
63-
$env:EVENT_SUBSCRIPTIONS_PATH = "providers/Microsoft.EventGrid/eventSubscriptions"
64-
$env:EVENT_SUBSCRIPTION_NAME = "RouterEventsSubScription_All"
65-
```
55+
## Quick-start: Receive EventGrid events via an Azure Storage Queue
6656

67-
**Create a new event subscription for Router events**
57+
### Create a new C# application
6858

69-
Copy and paste the following json payload in a text file named `test.json`.
59+
In a console window (such as cmd, PowerShell, or Bash), use the `dotnet new` command to create a new console app with the name `EventReceiver`. This command creates a simple "Hello World" C# project with a single source file: **Program.cs**.
7060

71-
*Sample payload*
72-
```json
73-
{
74-
"properties": {
75-
"destination": {
76-
"endpointType": "WebHook",
77-
"properties": {
78-
"endpointUrl": "<insert_webhook_path_here>"
79-
}
80-
},
81-
"filter": {
82-
"includedEventTypes": [
83-
"Microsoft.Communication.RouterJobReceived",
84-
"Microsoft.Communication.RouterJobClassified",
85-
"Microsoft.Communication.RouterJobLabelsUpdated",
86-
"Microsoft.Communication.RouterJobClassificationFailed",
87-
"Microsoft.Communication.RouterJobCompleted",
88-
"Microsoft.Communication.RouterJobClosed",
89-
"Microsoft.Communication.RouterJobCancelled",
90-
"Microsoft.Communication.RouterJobExceptionTriggered",
91-
"Microsoft.Communication.RouterWorkerOfferIssued",
92-
"Microsoft.Communication.RouterWorkerOfferAccepted",
93-
"Microsoft.Communication.RouterWorkerOfferDeclined",
94-
"Microsoft.Communication.RouterWorkerOfferRevoked",
95-
"Microsoft.Communication.RouterWorkerOfferExpired",
96-
"Microsoft.Communication.RouterWorkerRegistered",
97-
"Microsoft.Communication.RouterWorkerDeregistered"
98-
],
99-
"subjectBeginsWith": "",
100-
"subjectEndsWith": ""
101-
}
102-
}
103-
}
61+
```console
62+
dotnet new console -o EventReceiver
10463
```
10564

106-
**Create the event subscription**
107-
```powershell
108-
armclient put "$env:ACS_RESOURCE_ARM_ID/$env:EVENT_SUBSCRIPTIONS_PATH/$env:EVENT_SUBSCRIPTION_NAME/$env:API_VERSION" .\test.json
65+
Change your directory to the newly created app folder and use the `dotnet build` command to compile your application.
66+
67+
```console
68+
cd EventReceiver
69+
dotnet build
10970
```
110-
**Output**
11171

112-
:::image type="content" source="media/create-subscription.png" alt-text="Create event subscription":::
72+
### Install the packages
11373

114-
As we can see, the event subscription is being created and is currently in a state of `Creating`. It generally takes a few seconds to create.
74+
Install the Azure Storage Queues and EventGrid packages.
11575

116-
**Verify the event subscription was successfully created**
117-
```powershell
118-
armclient get "$env:ACS_RESOURCE_ARM_ID/$env:EVENT_SUBSCRIPTIONS_PATH/$env:API_VERSION"
76+
```console
77+
dotnet add package Azure.Storage.Queues
78+
dotnet add package Azure.Messaging.EventGrid
11979
```
12080

121-
**Output**
122-
123-
:::image type="content" source="media/verify-subscription-created.png" alt-text="Verify subscription was created":::
81+
### Receive messages from the queue
12482

125-
As we can see the event subscription has been successfully created now for all Router events.
83+
Copy the following code snippet and paste into source file: **Program.cs**
12684

127-
## Creating a subscription with filters
85+
```csharp
86+
using Azure.Storage.Queues;
87+
using Azure.Messaging.EventGrid;
12888

129-
While setting up event subscriptions, you can also use advanced filters controlling the exact events that needs to sent to a particular subscription. For example, given the sample below, only `RouterJobCancelled` events are subscribed to and sent to the webhook under the following conditions:
89+
// For more detailed tutorials on storage queues, see: https://docs.microsoft.com/azure/storage/queues/storage-tutorial-queues
13090
131-
- The job **priority** is greater than `5`
132-
- The job was assigned to an escalation queue
133-
- The job was canceled due to inactivity
134-
- The disposition code for canceled Jobs ends with `_JobCancelledDueToInactivity`
135-
- The Queue ID ends with the name `EscalationQueue`
91+
var queueClient = new QueueClient("<Storage Account Connection String>", "router-events");
13692

137-
```json
93+
while (true)
13894
{
139-
"properties": {
140-
"destination": {
141-
"endpointType": "WebHook",
142-
"properties": {
143-
"endpointUrl": "<insert_webhook_path_here>",
144-
"maxEventsPerBatch": 1,
145-
"preferredBatchSizeInKilobytes": 64
146-
}
147-
},
148-
"filter": {
149-
"subjectEndsWith": "_JobCancelledDueToInactivity",
150-
"isSubjectCaseSensitive": true,
151-
"includedEventTypes": [
152-
"Microsoft.Communication.RouterJobCancelled"
153-
],
154-
"advancedFilters": [
155-
{
156-
"operatorType": "NumberGreaterThan",
157-
"key": "data.priority",
158-
"value": 5
159-
},
160-
{
161-
"operatorType": "StringEndsWith",
162-
"key": "data.queueId",
163-
"values": [
164-
"EscalationQueue"
165-
]
166-
}
167-
],
168-
"enableAdvancedFilteringOnArrays": true
95+
var msg = await queueClient.ReceiveMessageAsync();
96+
if (msg.Value == null)
97+
{
98+
await Task.Delay(TimeSpan.FromSeconds(1));
99+
continue;
169100
}
170-
}
171-
}
172-
```
101+
var json = Convert.FromBase64String(msg.Value.Body.ToString());
102+
var evt = EventGridEvent.Parse(BinaryData.FromBytes(json));
173103

174-
Copy and paste the above json payload in a text and name it `test-with-advanced-filters.json` then execute the following PowerShell code:
104+
Console.WriteLine($"Received event: {evt.EventType} - {evt.Subject} - {evt.Data}");
175105

176-
```powershell
177-
$env:API_VERSION = "?api-version=2020-10-15-preview"
178-
$env:EVENT_SUBSCRIPTION_NAME = "RouterEventsSubScription_WithFilters"
179-
armclient put "$env:ACS_RESOURCE_ARM_ID/$env:EVENT_SUBSCRIPTIONS_PATH/$env:EVENT_SUBSCRIPTION_NAME/$env:API_VERSION" .\test-with-advanced-filters.json
106+
await queueClient.DeleteMessageAsync(msg.Value.MessageId, msg.Value.PopReceipt);
107+
}
180108
```
181109

182-
**Output**
110+
### Run the code
183111

184-
:::image type="content" source="media/advanced-filters.png" alt-text="Advanced filters output":::
112+
Run the application from your application directory with the `dotnet run` command.
185113

186-
> [!NOTE]
187-
> For a complete list of operators that can be used while creating subscriptions, refer to [Event Grid | Event Filtering - Operators](../../../event-grid/event-filtering.md)
114+
```console
115+
dotnet run
116+
```
188117

189118
## Events Catalog
190119

@@ -874,3 +803,7 @@ armclient put "$env:ACS_RESOURCE_ARM_ID/$env:EVENT_SUBSCRIPTIONS_PATH/$env:EVENT
874803
| Attribute | Type | Nullable |Description | Notes |
875804
|:--------- |:-----:|:-------:|-------------|-------|
876805
| workerId | `string` ||
806+
807+
<!-- LINKS -->
808+
[event-grid-overview]: ../../../event-grid/overview.md
809+
[filter-events]: ../../../event-grid/how-to-filter-events.md

0 commit comments

Comments
 (0)