As the market leader in the recrurring customer and billing management space, Zuora's Central Platform is expected to provide rich communication capabilities. For example, sending an email to our customers when a payment method is updated, or firing callouts that trigger downstream integration endpoints as billing events take place.
All of these communications are based on business events, which are business-relevant changes for our customers on the Zuora platform. Today, Zuora supports 24 predefined events limited to Billing, Payment and Finance domains; but our customers are asking for more. A lot more!
The Existing Event Framework
The design of Zuora’s event framework, conceived 6+ years ago, doesn't make it easy to add new business events; given the somewhat archaic nature of the framework, adding a new event isn’t a trivial operation, requiring new coding, and pulling in valuable resources from more important product roadmap work. Having identified some of the limitations with the existing framework, we decided to build a more modern, scalable framework which allows customers to define custom business events for themselves.
To solve the problem of an old and non robust event framework, we defined a flexible expression language to define event triggering conditions against the Zuora Object Model. The model, shown in Figure 1, should be familiar to our customers. When an object changes, conditions defined on the object are evaluated against the change, and a business event is triggered if one of the conditions is met.
Figure 1 - Zuora Object Relationship
Expression Language Examples
For example, a triggering condition defined on an Invoice object may look like this:
The condition is to trigger an event when an invoice is posted with amount over $1000. The expression itself is a JEXL expression, but we customized it by adding conventions and keywords to adapt to our domain use cases, for example:
changeType is a keyword to specify what kind of change happened to the object. Its acceptable values include INSERT, UPDATE and DELETE
Invoice.Status refers to field Status of Zuora object Invoice
Variables with _old suffix represent a previous value of the corresponding object field
Moreover, JEXL built-in functions can be used as well. We can even define conditions on custom fields, which is very hard to implement in hard-coded manner because custom fields are customer/tenant specific. Here’s one real example:
TradingPartnerCode__c is a custom field defined by a Zuora customer for use in their tenant.
Micro-Service Based Design
Beneath the surface, there are several services working closely to support this new approach to triggering business events. The various components are shown in Figure 2, below. A glossary follows describing the components represented in the figure:
Figure 2 - Service Components for the new event framework
CDC (Change Data Capture): Sends changes from the database to the Database Change topic in Kafka. Specifically, this component extracts mysql binlog then packages table row changes into a message.
Kafka: Messaging infrastructure we rely on to publish and subscribe to streams of messages.
Transformer: Consumes Database Change topic and translates the low level row changes into high level business object changes, and then sends them to the Object Change topic.
OCP (Object Change Processor): This component is where the triggering conditions are evaluated. It consumes Object Change messages, triggers out business events based on the mechanism explained above, and sends events to the Business Event topic. Also, REST APIs are provided for customers in order to manage event triggering conditions.
When a business event is triggered, the payload is loaded with all the facts related to the object change, including the snapshot of the current field values, the previous values, the timestamp, and other metadata for debugging purposes. The downstream services, like the Notification service, can then consume messages from the Business Event topic and send out emails to our customers, or fire callouts to customer integration points.
With the simple customized expression language and the above set of services, nearly any change event that takes place on Zuora’s object model can be defined and detected. This new framework is more robust and scalable than the predefined approach but with any new framework, there are enhancements we are looking at adding to the new framework in the future, including support for more Zuora objects, multi object changes, ordering and latency enhancements.