This article is part of #ServerlessSeptember. You'll find other helpful articles, detailed tutorials, and videos in this all-things-Serverless content collection. New articles from community members and cloud advocates are published every week from Monday to Thursday through September.
Find out more about how Microsoft Azure enables your Serverless functions at https://docs.microsoft.com/azure/azure-functions/.
Follow me also on my YouTube Channel: CoderDave
In this post I want to show you how serverless could be beneficial even in the enterprise context.
To do so, I will tell you a real story of a real enterprise I've helped creating an EIP, enterprise integration platform, which is completely Serverless.
The need of this enterprise was very similar to many other realities around the globe.
They had dozens of different systems that needed to communicate with one another, and they wanted to do so in a reliable, simple but yet inexpensive manner.
Of course, as you would expect, the landscape of those systems is very heterogeneous:
- some platforms have APIs, some haven't
- on some system you need to connect directly on the database
- some of the systems are hosted on-prem, while some others are hosted in Azure
Since they had to create it from scratch, the company also wanted their yet-to-be-born EIP to fulfill a series of requisites that sound pretty reasonable. The EIP had to:
- Connect all the systems using some sort of standardized approach
- Allow both synchronous and asynchronous communication
- Handle unpredictable load peaks, as well as scale down on the no load moment
- Be reliable
- Ensure consistency
- Had little or reduced maintenance cost and overhead
- Everything should be managed via CI/CD
Each of those points is fair, but the challenge was to achieve them all within the same platform.
Luckily for them (and for us), Azure has all we need for achieving those goals.
We decided to create the entire EIP using these 4 services:
- Azure Functions
- Logic Apps
- Service Bus
- API Management
All of them can automatically scale based on load or custom metrics, to help handling load and reduce cost.
After a few architectural sessions, and some implementation, this is what we came out with:
As you can see, there are 2 main flows: the API flow and the Message Queue one.
Let's start with the APIs. The main component here is API Management; all the APIs (for all the services that have APIs...) are masked and exposed by this service, for both on-Azure and on-prem (thanks to the VNet integration).
This allows for standardizing the APIs methods, verbs and request/response objects since APIM can easily translate them for us.
If no APIs are available for a certain operation and to ensure the async support, we also implemented the Message Queue flow.
One (or more) Azure Functions have been developed for each system, and they respond to that very system events. They take the payload of that an event and push a message into Service Bus.
But that's not enough, because remember that we want to achieve standardization. For this reason, each Azure Functions massage the data of the payload and create a message in a standard format and only then they write to Service Bus.
And since the message at this point has a standard format and properties, it can easily be picked up from a Logic App that orchestrate the response process. Once again, we have multiple Logic Apps for multiple systems, and depending on the destination system and the message content they may invoke some APIs, write to the DB, and what not. Of course, each set of Logic Apps has a subscription only to the appropriate messages.
This was already a good solution, but not a perfect one. In fact:
- async communication was not always provided (especially when invoking APIs directly)
- the system couldn't handle the online/offline status of the services (for example during maintenance or update windows)
- there was no way for the users to interact manually with the EIP
For the above reasons, we decided to expand the v1 into the v2 of the EIP:
The foundations of the v2 are the same, but we introduced some more "components".
First of all, we decided to create some Online/Offline handlers, using once again Azure Functions. Those are very useful, especially when the systems are interacting with the APIs, because they allow for handling any problems during communication. If a system is not reachable because it's down for maintenance, or there is a network problem, or yet a transient error occurs, these handlers compose a new message and save it into Service Bus. Each message has a property which indicates if it's an "original" message or, like in this case, a "retry". If it is in fact a retry, there is also a "retry times" property which is incremented every time. To avoid flooding the system with retries, a configurable retry threshold is in place and if the number of retries is reached for a specific message, the message is discarded (aka put in a specific errors queue) and a high priority alert is generated.
Also, we've created a Web App (which once again publish messages to the MQ via an Azure Function) to allow users to send messages into the EIP, targeting predefined operations in specific systems. This, as you can see in the diagram, follows the same patterns and principles of the other flows and systems.
In one word: yes!
- Everything used is Serverless, so has very little maintenance, management cost/effort, and scales up and down pretty easily
- The Combination of Azure Functions and Logic Apps, together with Service Bus, allows to create a fully sync/async platform
- The messages and format used have been standardized, and so are the APIs thanks to API Management
- The online/offline handlers ensure reliability at application level, while Azure (and the services SLAs) does so at platform level
- All the code (including Functions and Logic Apps) is stored into, and validated and deployed with Azure DevOps, achieving full CI/CD
We also went beyond what the initial requirements were:
- Quotas were implemented into API Management to prevent accidental DoS
- API Management also help controlling the execution and the security of the APIs, which some systems didn't have in place
- The entire EIP is under monitoring, thanks to Azure Monitor and Application Insights
Although this is an almost perfect EIP (at least it is for us), there are some small notes and gotchas worth sharing.
- Azure Functions in Consumption mode doesn't support VNet integration
- You need to use other hosting plans (i.e. Premium, Dedicated, etc.) if you want to connect to on-prem
- CI/CD for LogicApps is not exactly fun
- LogicApps workflow definition language must be manually parametrized
- Then ARM Template can be grabbed, but
- ARM Template must be manually modified to set parameters value
- There is no Azure Functions Specific build and deploy task in Azure DevOps
- You need to use the Asp.Net Core task
- Depending on your configuration, you may need to use customized deployments settings