The release of Notifications 2.0, the new Cumulocity notifications API, beta in 10.13 and subsequent trial availability on eu-latest.cumulocity.com earlier this year, has allowed Cumulocity product management and development to gather some valuable feedback and schedule development of a round of enhancements planned to be released in 10.16.
Currently still an optional feature in 10.14 & 10.15, as it requires enabling the new Message Service, Notification 2.0 is being rolled out to all hosted environments, with the expectation that it will become a standard feature soon.
Thanks to all who have contributed to this evaluation and provided feedback! This blog post describes some enhancements resulting from your feedback that will be available in the upcoming Cumulocity 10.16 release. We first describe two minor usability enhancements before introducing shared and nonpersistent subscriptions and the new filtering features.
Unsubscribe a Subscriber
One API enhancement that was made in 10.14 is the ability to unsubscribe a subscriber from Notification subscriptions. In normal usage, a subscribing application would simply delete the subscription using the “remove subscription” API. No new notifications would then be captured and persisted, and the application would drain down (by consuming) any remaining stored notifications.
However, in some cases (e.g., development/deployment lifecycle scenarios), an application can be removed without first draining down notifications, so an additional mechanism to “unsubscribe” a notification consumer is required.
In 10.14, this is possible to do both in-band on the Web Socket protocol and via a new REST endpoint. To unsubscribe over the Web Socket, just send an “unsubscribe_subscriber” string back to the WebSocket server instead of a message acknowledgement on a single line (i.e., command string terminated by “\n”).
For out-of-band unsubscribing, the new control endpoint is “/notification2/unsubscribe” and a token for Notifications (created using the Notification 2.0 create token API and which names the subscriber) can be posted to that endpoint, supplying it as a query string “token” argument:
curl -X POST -u <username>:<password> https://<your_cumulocity_domain>/notification2.0/unsubscribe?token=”<your-jwt-token>”
“Get subscriptions for” Enhancements
With the original “retrieve” Notification 2.0 API, it was possible to get subscriptions on a particular managed object (the “source”), or to get all subscriptions under a tenant. We’ve enhanced this by allowing all subscriptions with a particular “subscription name” to be retrieved. This should help in managing subscriptions on multiple managed objects that feed into the same notification topic – which is a very common use case that uses a single subscription name for the aggregated common topic.
It’s also now possible to retrieve all subscriptions that include a given type filter value by allowing a retrieve of all subscriptions in a context that match a particular string literal in their “type” filter. Please see the 10.16 API preview when it becomes available for details and note that you can now have multiple type filters as described below, here we are just checking for one particular “type” filter value.
Shared Subscriptions for Scale Out
If an application needs to subscribe to a high volume of notifications or if processing of notifications requires considerable time, then one common approach is to scale the subscribing application or consumer horizontally.
When creating a token for consuming notifications, it is now possible to specify that the consumer will not be exclusive, but that instead consuming will be “shared” between a set of consumers. This is done by creating the token via a REST request that has an extra (and optional, defaulting to false) “shared=true” query parameter.
The number of consumers can then vary as the application instances scale up or down, and notifications will be sent to one or other of the current set of consumers. To aid in this, consumer connections on the WebSocket endpoint should specify a unique consumer name (using another query parameter consumer=). E.g,
wss://<your-environment-or-tenant>/notification2/consumer?token=<jwt-token>&consumer=<the-consumer-instance>
The details are given in the User documentation for this feature. One important consideration is the order of notifications from a single source device (or managed object). Notifications will be delivered in-order for any device, but, as consumers start or stop/fail, delivery of notifications from a particular device may switch to another consumer. Providing the above consumer name, on WebSocket connection, to consume notifications helps achieve this. Please see the user documentation messaging reference section for 10.16 for further details when it becomes available.
Non-persistent Subscriptions
By default, notifications will persist in the message service until consumed and acknowledged by all subscribers. There can be more than one subscriber, but usually just a single subscriber who must consume the message with an acknowledgment – each subscriber though, with shared subscriptions, may now consist of a load balanced set of consumers.
Subscriber acknowledgment on processing is how “at least once” semantics are achieved, but mean duplicates can be delivered if, for example, an acknowledgement is not sent or received by the messaging service in time and can be costly to track persistently.
As an experimental Notification 2.0 new feature, it is possible to create non-persistent subscriptions that only deliver notifications when subscribers are active and that limit the number of unconsumed notifications to a low limit (1000 by default) of in-memory backlog.
To use non-persistent subscriptions, both the subscription and the notification token(s) must be created with a nonPersistent=true optional query parameter. The default, as before and for almost all use cases, is persistent (nonPersistent=false). Again, please see the 10.16 preview user documentation for further usage details.
As the delivery semantics for non-persistent subscriptions is “best effort” and the performance of normal persistent subscriptions is typically not an issue, non-persistence is not a typical use case but one we believe is still important to enable, especially as it can approximate the original Realtime notification API semantics.
Both shared and nonPersistent subscriptions must be explicitly enabled in 10.16 deployments. We hope to make them enabled by default under Notification 2.0 after 10.16.
Notification Filtering
Specific filters have been added to allow a managed object’s and its children’s alarms and events to be selected. The API filters for this is “alarmsWithChildren” or “eventsWithChildren” and selecting these (new) filters allows alarm or event notifications from both the managed object that the subscription is created for, as well as all it’s children (transitively) to be subscribed to. This avoids having to make a subscription on each of the children or selecting the ALL (“*” or wildcard) API filter on the parent object (which has the disadvantage of also subscribing inventory and other notifications, which could be frequent or large). This feature is already available in 10.15.
We’ve also allowed multiple “type” filters to be set. Alarms, events and measurements normally carry a “type” JSON fragment with a string value, and it was already possible to filter this by a single match value. Now multiple match values can be filtered for, by specifying an ODATA expression that consists of a single value or multiple values separated by a logical “or”. Other ODATA expressions are currently not allowed.
e.g., ODATA expression with quotes and unnecessary brackets for demonstration purposes:
'type-value1' or (“type-value-2” or ‘type-value3’)
It is also now possible to filter for events of one or more “type” in the tenant context (i.e., all tenant events with a particular “type” filter). This third filtering enhancement, which extends what was already possible for Alarms and managed object creation notifications at the tenant level, by allowing filter of all events in a tenant with one subscription (made in the tenant context), as long as, one or more type values to filter on are given for matching.
It’s still not possible to subscribe to all measurements at the tenant level as this could generate a very large volume of notifications for tenants. Apart from the filtering cost, the concern is message storage and processing costs and having microservices consume large numbers of unnecessary notifications – so even these filtering extensions must be used carefully. For measurement notifications, individual managed objects must still be subscribed.
Future Enhancements
Further filtering enhancements have been requested and may be added in the future. One common use case is filtering by a particular “fragment” or “root node” in the notification JSON.
One common suggestion is to be able to subscribe to notifications from multiple managed objects in one REST request. While this can be done by repeatedly calling the create subscription API, allowing a list of managed object identifiers to be given will help with this common use case and also help to make it clearer that the same logical subscription (i.e. using the same subscription name as a single subscribe-able topic) can be made on multiple managed objects.
The Notification 2.0 API is being used to provide Cumulocity connectivity to webMethods.io which will enable more integration scenarios which will also be enhanced with more filtering options in future. For direct usage, we also hope to provide more comprehensive examples of API usage in the form of microservice samples, so please stay tuned for more updates.
We, the Cumulocity development team who worked on Notification 2.0 and enhancements, would like to thank early users of Notifications 2.0 and we hope that these enhancements, coming together soon in 10.16, will help with your use cases for the new Notification 2.0 API. If you have additional use cases, requirements, or suggestions, we would love to hear them.