The above log is the only way to verify that the UA call is successful so far, because the client web page hasn’t been implemented yet.

This article by Zhongming Chen, published on the ASOS Tech Blog, has some very good notes about Azure Functions, so take a look if you’re planning to use them.

5 — The web front-end

The last step involves creating the client app, which is a website or, rather, a single web page for this demo. In a real-world implementation there would be product listing pages and product details pages getting data from something like a Product Catalog API, and, as part of the product attributes returned by the API, there would be something like an ‘isInStock’ attribute. When that’s false, the customer might click a button to register their interest for the product, and the notify-instock-{productId} described before would be associated to them.

For the purpose of this article however, the simplest, and ugliest page — with a static list of three product names and a ‘Notify’ checkbox on their right-hand side will do just fine. The UA client-side SDK, as well as the initial configuration, is fully explained on this page, but here’s the gist:

Download the zip with the JS files from the UA configuration page and upload the push-worked.js file on the root folder of the website.

Make sure SSL is enabled on the website/domain (you can use CloudFlare to do this for free and with a couple of clicks, if you don’t have this already). If this and the previous step are not done correctly, you risk wasting a lot of time figuring out why the implementation doesn’t work…

Create the HTML page, which:

1) imports the JS snippet that loads the Urban Airship’s JS SDK.

2) when the SDK is loaded, checks the isSupported and canRegister properties, and, if they’re true, calls the register function to have your browser ask the customer for the permission to send push notifications.

3) handles the click on the checkboxes to add/remove the notify-instock-{productId} tag.

Here’s the full HTML/js code:

When the page loads for the first time (or even subsequently, if you just cancel the prompt for the notifications) this is what you should get:

Click ‘Allow’, and then tick the ‘Notify’ checkbox for one or more products:

Note how successful I was in creating the ugliest page ever.

Finally, use the Console app to send a ‘instock 123’ command. If everything is set up correctly, you should get a notification like this on Chrome (even if you’re on another page of course):

On a Mac, the notification will also be shown on the system-level Notifications panel on the right-hand side of your desktop:

Please note: don’t despair if you don’t immediately get a notification. It sometimes takes a few minutes to show up, after you see the log on the Urban Airship console.

Urban Airship and the other third-party providers abstract a lot of details. If you want to better understand how the Web Push Protocol works behind the scenes, start from this page. By using third-parties, it spares you the need to create all the infrastructure to record the IDs of the devices that register to get the notifications (ie: a DB with a table of device IDs, their tags etc.) and all the work to send the notifications to all targeted devices. After you make a single call to Urban Airship targeting a tag, it might mean 1M calls that UA does on your behalf, one per device, if there are 1M users/devices registered for that tag. You can easily see how not having to worry about that is good.

EXTRA — Adding a filter for the BackInStockNotifications subscription

When you create a new Azure Service Bus Topic subscription through the Azure Portal, you won’t have the option to set up a ‘filter’, which means that all new messages for that Topic will be copied into the subscription. However, you might only want to process a sub-set of messages, not all. In the scenario described in this article, only messages with ‘IsInStock = true’ need to be processed, assuming that customers only want to be notified when something they liked is back in stock…and they don’t need to be notified about something going out of stock (that might be a reasonable option as well in reality, but not for the purpose of this demo).

The way it works so far is that there’s an if statement when the Function starts and the json data is decoded into a ProductStockChanged message. While this works, it’s not optimal, because it means the function is going to be executed plenty of times for messages it doesn’t need to process — this means wasted compute time, which in turns means additional instances being necessary and additional cost. A better solution is to create a subscription with a rule/filter, so that only messages matching certain conditions are copied into it for further processing. It’s not possible to create the filter directly from the Portal unfortunately, but luckily, it’s simple enough to do it programmatically (in a method that you could execute from a management console app or something similar). Here’s the method that modifies the existing subscription by adding a SqlFilter for ‘IsInStock = true’:

Additional examples in this article

The SqlFilter can refer to attributes defined in the message’s UserProperties array, not on attributes defined directly in the json (because the message’s body could be plain text, json, xml or anything else)…so now line #67 of the Console app’s code displayed in Section 2 of the article should be clearer.

After executing this code, use the Console app to send some ‘outofstock {id}’ commands, and you’ll see that they’ll end up in the UpdateCatalog subscription (the second subscription I had created at the beginning, with no filter), but not in the BackInStockNotifications subscription. A much better result. (I still left the check in the Function itself as well though, just in case the filter doesn’t work or is removed by mistake.)

An even better solution that doesn’t require executing custom managed code as part of your deployment/configuration pipeline is using the Azure CLI as described here.

Possible further enhancements

This was meant to be a POC, but in a real implementation you will very likely want to consider the following aspects when sending out push notifications:

Support multiple languages: this might be as easy as targeting the notifications with a language tag (eg: lang_fr) in addition to the notify_instock_{productId} tag. The Azure Function would call UA once for every language (so five times if you support five languages), but a customer would only get one notification because they would only be registered for a single language tag. Some third-parties also allow the use of ‘templates’, where the body/content of the notification is dynamically injected by the provider itself according to the language or other conditions. The technique above, albeit more primitive, should work with all though.

Enrich the notification with the name of the product, price or other information. As mentioned previously, this info could be part of the Service Bus Message itself (which would be super simple to add), or otherwise could be retrieved dynamically by calling another API, such as the Product Catalog API. Though there would need to be an additional caching layer, the Product Catalog API would potentially need to be scaled up to support the additional load.

Currently, the notification always opens the homepage of the website when clicked because the default action url defined at the project configuration time wasn’t overridden on the specific notification. It would be better instead to add a url/deeplink to the notification, so that the product details page is loaded when the notification is clicked. All third-party providers allow this as it’s a basic requirement, but of course the syntax/attributes on the input json vary by provider (each has its own proprietary json, since they abstract the real content of the lower-level platform-specific notifications).

Conclusions

That’s all folks. Albeit quick and simple to set up, the proposed implementation is quite powerful and flexible, as it’s based on loosely coupled components (the checkout and stock microservices know nothing about the Function that handles the stock-related messages to send push notifications) and it offers great scalability (the Azure Function will be scaled up automatically according to how many messages it has to process). Last but definitely not least, the use of Service Bus offers a better overall reliability of our system, because if the delivery of the notification fails for any reason (eg: Urban Airship is down), the Function fails, the message goes back into the queue and it will be processed again later. Hooray Azure!