Hosting LitwareHR on a Service Delivery Platform - Part III - Billing, Metering
Billing is obviously a very important concern, after all Litware has to get paid! As described in Part I, Litware is looking at two models for Billing:
• Subscription based: (For example: $X/tenant/month up to 5 seats/tenant + $Y/month for additional seats)
• Usage based: $Z/"Submitted Resume"
In our imaginary scenario, we'll assume that Litware billing requirements are easily met by NWH billing capabilities. NWH Billing system supports these two modus operandi and offers rich customization, reporting, tax considerations, etc. So, for the purposes of this exercise, NWH Billing is state of the art.
But the question is: how does NWH Billing know what and when to bill? or in other terms, how to "glue" LitwareHR to the billing system? And, more importantly from Litware perspective is how intrusive this is. Remember, Litware is willing to change the app, but only if benefits they get out-weight the liabilities.
Everybody favors a non intrusive mechanism, because it minimizes changes to the app. Not by chance, NWH knows that the least requirements and constraints the more ISV they will attract.
NWH Application Model actually makes this fairly easy, by using an interception mechanism:
Figure 1 - Northwind Hosting Operations Interception
Because the application is expected, by design, to expose all it's functionality through WCF web services, it gives NWH the chance to intercept all traffic to it (between the Web Client or any client calling the app web services. WCF provides a very powerful foundation for this kind of architecture (see behaviors and message inspectors).
What NWH does is very simple:
- When the application is on-boarded, it looks in the app manifest for any "Business Action" definition (remember, Business Actions are just "managed" Operations) and stores any information in the Business Action database.
- One of the pieces of information is a "Billable Event". A name that identifies the billing event that is triggered each time the associated Operation is invoked.
- At runtime, the interceptor will forward the event to the Billing System for processing.
The sub-optimized interceptor in pseudo-code is illustrated in Figure 2. Message represents the incoming request, Operation is the Action being invoked, CurrentContext represents the contextual information associated with this particular invocation (It will normally contain the tenant identifier, credentials, and any other out-of-band data).
Figure 2: Pseudo-code for an interceptor
Notice that the first thing the interceptor checks, is if the Operation is enabled or not. "Enabling/Disabling" an Operation allows NWH to put a gatekeeper for execution. This might be necessary when a request arrives from an overdue tenant for example. The Billing system might flip the bit for those in debt automatically as hinted in Figure 1.
This mechanism perfectly serves Litware's requirement of "turning the application to read-only" for non-paying customers. But there might be other good scenarios for this feature: isolating malfunctioning operations, maintenance, etc. The Control Panel allows manipulation of the metadata for users or NWH Operators.
Notice there's no change required in Litware if it complies to the Application Model.
Because nothing of value is free in this world, this approach has a cost. If the interceptor is poorly written it has the potential of causing a lot of trouble: degrading performance, bringing instability, etc. It is definitely a piece of code that needs some good developers assigned to it. A good implementation will use lot's of smart strategies like caching, short circuiting through appropriate configuration, asynchronous calls to decouple bill event processing from the main thread, etc.
Also, appropriate for the billing example. When should the event be generated? At the beginning or at the end of the execution? If whatever the Operation does fails and throws an exception, should the event be generated anyway? Or consider this: if the Operation runs in a transactional context, should the event be associated with the transaction? Real world interception mechanisms have all these provisions.
Now, if you are wondering whether this approach is actually used or not in the real world or if it's just Eugenio's design after drinking grappa , just take a look at CRM Live services design as presented in last MIX (red highlight is mine):
Figure 3: CRM Live Architecture