Skip to main content
Azure Notification Hub race condition
  1. Posts/

Azure Notification Hub race condition

·375 words·2 mins
Christoph Petersen
Author
Christoph Petersen
Table of Contents

Both development and production environments are deployed in a fully automated fashion using ARM templates. As part of these deployments we also create Notification Hubs and related authorization rules.

I noticed today that some of our deployments were failing due to the fact that the Notification Hub resource provider was not able to find a related resource although the necessary dependencies were defined.

Failed ARM deployment

With a little testing I was able to narrow it down to a race condition between the resource creation and resource operations such as listKey that act on the resource. I’ve put together the following brief template that will intermittently fail:

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "Name": {
            "type": "string"
        }
    },
    "variables": {
        "location": "[resourceGroup().location]",
        "locationHub": "[variables('location')]",
        "name": "[parameters('Name')]",
        "nameHubNamespace": "[variables('name')]",
        "nameHubHub": "[replace(variables('name'), '-', '')]",
        "nameHubAuthorization1": "Auth1",
        "nameHubAuthorization2": "Auth2",
        "nameHubAuthorization3": "Auth3",
        "nameHubAuthorization4": "Auth4"
    },
    "resources": [
        {
            "type": "Microsoft.NotificationHubs/namespaces",
            "apiVersion": "2017-04-01",
            "name": "[variables('nameHubNamespace')]",
            "location": "[variables('locationHub')]",
            "sku": {
                "name": "Free"
            },
            "kind": "NotificationHub",
            "properties": {
                "namespaceType": "NotificationHub"
            }
        },
        {
            "type": "Microsoft.NotificationHubs/namespaces/notificationHubs",
            "apiVersion": "2017-04-01",
            "name": "[concat(variables('nameHubNamespace'), '/', variables('nameHubHub'))]",
            "location": "[variables('locationHub')]",
            "dependsOn": [
                "[resourceId('Microsoft.NotificationHubs/namespaces', variables('nameHubNamespace'))]"
            ],
            "properties": {}
        },
        {
            "type": "Microsoft.NotificationHubs/namespaces/NotificationHubs/authorizationRules",
            "apiVersion": "2017-04-01",
            "name": "[concat(variables('nameHubNamespace'), '/', variables('nameHubHub'), '/', variables('nameHubAuthorization1'))]",
            "dependsOn": [
                "[resourceId('Microsoft.NotificationHubs/namespaces/notificationHubs', variables('nameHubNamespace'), variables('nameHubHub'))]"
            ],
            "properties": {
                "rights": [
                    "Send"
                ]
            }
        },
        {
            "type": "Microsoft.NotificationHubs/namespaces/NotificationHubs/authorizationRules",
            "apiVersion": "2017-04-01",
            "name": "[concat(variables('nameHubNamespace'), '/', variables('nameHubHub'), '/', variables('nameHubAuthorization2'))]",
            "dependsOn": [
                "[resourceId('Microsoft.NotificationHubs/namespaces/notificationHubs', variables('nameHubNamespace'), variables('nameHubHub'))]"
            ],
            "properties": {
                "rights": [
                    "Send"
                ]
            }
        },
        {
            "type": "Microsoft.NotificationHubs/namespaces/NotificationHubs/authorizationRules",
            "apiVersion": "2017-04-01",
            "name": "[concat(variables('nameHubNamespace'), '/', variables('nameHubHub'), '/', variables('nameHubAuthorization3'))]",
            "dependsOn": [
                "[resourceId('Microsoft.NotificationHubs/namespaces/notificationHubs', variables('nameHubNamespace'), variables('nameHubHub'))]"
            ],
            "properties": {
                "rights": [
                    "Listen"
                ]
            }
        },
        {
            "type": "Microsoft.NotificationHubs/namespaces/NotificationHubs/authorizationRules",
            "apiVersion": "2017-04-01",
            "name": "[concat(variables('nameHubNamespace'), '/', variables('nameHubHub'), '/', variables('nameHubAuthorization4'))]",
            "dependsOn": [
                "[resourceId('Microsoft.NotificationHubs/namespaces/notificationHubs', variables('nameHubNamespace'), variables('nameHubHub'))]"
            ],
            "properties": {
                "rights": [
                    "Listen"
                ]
            }
        }
    ],
    "outputs": {
        "connectionHub1": {
            "type": "string",
            "value": "[listKeys(resourceId('Microsoft.NotificationHubs/namespaces/notificationHubs/authorizationRules', variables('nameHubNamespace'), variables('nameHubHub'), variables('nameHubAuthorization1')), '2017-04-01').primaryConnectionString]"
        },
        "connectionHub2": {
            "type": "string",
            "value": "[listKeys(resourceId('Microsoft.NotificationHubs/namespaces/notificationHubs/authorizationRules', variables('nameHubNamespace'), variables('nameHubHub'), variables('nameHubAuthorization2')), '2017-04-01').primaryConnectionString]"
        },
        "connectionHub3": {
            "type": "string",
            "value": "[listKeys(resourceId('Microsoft.NotificationHubs/namespaces/notificationHubs/authorizationRules', variables('nameHubNamespace'), variables('nameHubHub'), variables('nameHubAuthorization3')), '2017-04-01').primaryConnectionString]"
        },
        "connectionHub4": {
            "type": "string",
            "value": "[listKeys(resourceId('Microsoft.NotificationHubs/namespaces/notificationHubs/authorizationRules', variables('nameHubNamespace'), variables('nameHubHub'), variables('nameHubAuthorization4')), '2017-04-01').primaryConnectionString]"
        }
    }
}

Workaround
#

I was not able to find a workaround contained to the ARM template. The only way to fix this intermittent error for us was to update the script that executes the template deployment and do a retry if the deployment fails.

Related

Setting App Service connection strings in ARM

·144 words·1 min
For automatic deployment of test environments we are spinning up App Service instances and want to automatically set connection strings for the database and other services in the same template.

Automation in Azure

·1125 words·6 mins
Deploying resources and workloads at scale requires a healthy amount of automation. Automation helps to deliver consistent and repeatable results. I’ve tried to categorize some of the technology and provide some pointers to areas of application and pros and cons.

Tracking changes to Azure Resource Manager providers

·65 words·1 min
A colleague of mine, Tyler Ayers, has written a pretty neat Azure Function that tracks changes made to Azure Resource Manager Providers (ARM) and show these changes in a timeline.