As the architect for the new Cumulocity IoT messaging service, I thought it would be a good idea to start a series of blog posts on Tech Communities about the new service and how we will be using it. These blogs will be technical in nature, so you will need to have a reasonable understanding of REST, MQTT and Cumulocity API.
This first blog introduces our new notification API, re-published here, why we have done it and what it looks like. A follow-on post looked at how the messaging service is implemented. At the time of this writing, the installation of the messaging service is optional, however the messaging service will become a standard part of the Cumulocity IoT platform. It’s recently been enabled on eu-latest.
Firstly, let us remember what the platform notifications provide: notifications are a major (downstream/north-bound) integration point for the Cumulocity IoT platform, allowing external applications and systems to react to events on the Cumulocity IoT platform. There are various platform events that can generate notifications, data via measurements, events or alarms as well as changes to managed objects.
Before 10.11, the only means to receive API notification was over the ‘realtime’ notification API using a somewhat complex “Bayeux” protocol. While suitable for some use cases, such as interactive user interfaces, delivery is very much a best-effort quality of service (QoS) where notifications could be dropped under load or on network or node failures.
The aim of the new notifications API, which has been named Notifications 2.0 to differentiate it from real-time notifications, can be summarized as follows:
- Keep the current set of notifications (measurements, events, alarms and inventory modifications)
- Provide a better QoS
- Allow notifications to be received over a simpler Web based protocol
The resulting new notification solution is built on the new Cumulocity messaging service. Currently an optional component in Cumulocity, the messaging service provides industry-leading performance, reliability and scalability. It is based on the open-source Apache Pulsar project, which implements both messaging and streaming at IoT scale. Our reasons for choosing Pulsar as well as experience applying it is discussed in the follow on blog post, here we would just like to note that it’s already used (again optionally) to enhance the Cumulocity data broker feature, providing robust forwarding of IoT events to a remote Cumulocity tenant. Please see the operations documentation or ask your Cumulocity administrator to enable messaging and the notifications API if you plan to try it out or give it a spin on eu.latest (note: requires permissions to create microservices which may have to be requested).
Getting back to our main subject, the crucial improvement Notifications 2.0 provide is “at least once” semantics. Once accepted by the Notification 2.0 service, messages will be delivered in order and repeatedly until acknowledged by the notification subscribing application (i.e. the notification consumer). This allows robust enterprise applications to be built more easily. The subscribing application, running as a Cumulocity microservice or externally, must cooperate with this by both acknowledging messages processed (via the new protocol) and be prepared to handle duplicate messages (very infrequently in practice).
As already mentioned, changes are only on the notification-subscribing and -consuming application side (often referred to as the “north side” with devices being “south side”), but please bear in mind that notifications are generated by any use of the Cumulocity API unless suppressed, also from Microservices, and that Microservices can be producers and consumers of Notifications 2.0 equally well.
To receive notifications, an application (such as a Cumulocity microservice), needs to subscribe for notifications on managed objects. This is done by a new Cumulocity notification subscription REST API. This is documented in the 10.11 Open API doc, but we won’t go into exact details here – only to mention that you can have more than one subscription on any managed object and that the subscriptions can share a subscription name, whicheffectively becomes a shared topic for consuming notifications. So, for example, it is possible to subscribe all printer objects, say in a region, to an ink ordering application that monitors ink levels on a particular subscription topic without the printers needing to “send to” or otherwise reference the subscription. This allows notifications to be routed to interested consuming applications, which only have to specify the particular name of the subscription they want to listen to. In addition, simple filtering and notification fragment selection can be configured for each subscription created.
A subscription consuming application uses a WebSocket connection to receive and acknowledge notifications over TLS/SSL. The connection requires a JWT (JSON Web Token) to authenticate the connection. This token is obtained using the new notification token creation API of Cumulocity, using normal tenant/user authentication, with the resulting token being valid for a limited time for connection. The token can be passed to another application or external service, so it’s not strictly limited to a tenant and must be protected. It can be refreshed after expiry relatively simply, but this requires valid Cumulocity tenant/user credentials (as well as a new Cumulocity role allowing specific users to create notification tokens).
The new protocol consists of a series of notification “pushes” from Cumulocity to the subscription-consuming application, each of which the application must acknowledge, which provides the end to end “at-least-once” semantics. The web socket protocol is text-based, and Cumulocity sends out a series of headers followed by a blank line and the notification body. The first message header is the acknowledgment identifier string that must be returned to acknowledge the notification. The following headers specify the type of notification (measurement, event etc.) and the API action performed (CREATE, DELETE etc.). The following “body” of the notification is the JSON API request possibly filtered for a fragment of interest. Our user documentation and sample provide fuller details.
To get you started with these new APIs, we have made a simple microservice sample available. This subscribes to a particular managed object’s notifications and consumes any notifications the real or dummy test device generates using the new Notification 2.0 web socket protocol.
In addition to managed object subscriptions, there is another “context” for subscriptions at the level of a tenant. Subscribing at the tenant context allows all managed object creations to be notified as well as all alarms to be intercepted. In the future, more platform-level notifications may be added under this or an additional notification context. So if you have additional use cases for new types of notifications, then please let us know!
In this initial version of the new notification API we shall be providing single consumers of subscriptions, which places a limit on scaling the integrations unless some logical partitioning of processing can be leveraged. This (shared subscriptions) and some other aspects of building scalable microservices will be addressed in future community releases.
One feature of real-time notifications not supported by Notifications 2.0 are “subscribe all” or “wild card” subscriptions, due to being inherently not scalable. Also, subscription is currently not possible at a managed object group level (which is often the use case underlying ill-fated attempts to use wild cards) or interactively via UI, but such use cases could be supported on top of the new notification mechanism in the future.
Notifications can be generated for events and measurements without persisting the measurements or events in the Cumulocity data (using Transient mode). With Notifications 2.0, these can be consumed and captured reliably by a user application subscribing to the “stream” of incoming notifications. This allows an application to filter, aggregate or otherwise compress events before persisting in the Cumulocity data store (being careful to use Quiescent mode to avoid an infinite loop here). We hope that this architectural pattern allows a new type of robust, scalable application to be built on Cumulocity. One motivation for this blog post is to motivate and champion such new architectural IoT patterns. Please expect more samples and developer examples for actual use of the new notification API and protocol.
Given the initial experience with Notifications 2.0, we plan to make it the default integration solution going forward, becoming always enabled by default and deprecating the original “real-time” notifications, except for legacy cases, as well as encouraging removing anti-patterns such as polling the inventory.
We hope to enhance the solution with scalable “shared” subscriptions as well as non-persistent “volatile” topics in the future, as well as adding more types of notifications.
As Cumulocity developers, we welcome your use of and feedback on the new Notifications 2.0 API, to help make this exciting leap in ease and robustness of integration.
Andre Kramer, Architect for Cumulocity Messaging.