Serverless systems are all the rage these days, and why not? They are, in my view, the next evolution on the microservice architecture that has been quite common over the last few years. But they offer several benefits such as they require no infrastructure deployment and, within most cloud environments, can easily integrate with and respond to the events happening within the cloud system.
The two leaders in this category, as I see it, are Amazon (Lambda) and Microsoft (Azure Functions). I thought it would be useful to walk through creating a simple Image Processing Microservice and discuss the various pieces of the implementation, from planning to completion.
One of the most critical pieces in software development is planning, and with Cloud this is even more vital as the sheer number of ways to accomplish something can quickly create a sense of paralysis. It is important that, for your chosen Cloud provider, you understand its offerings and have some idea how things can integrate and how difficult that integration may be versus other routes.
This planning is not only for the archiecture and flow of the coming application but also a means to facilitate discussion with your team. For example, understanding that serverless may not be the best choice for everything. Serverless functions can take a while to spin up if they are not used often. Further, most serverless providers cap the execution time of a given function. Understanding these and other shortcoming may lead you down the road of a more traditional microservice using Docker and infrastructure, going purely serverless, or a hybrid of the two.
For our Image Processing application, I have concocted a very simple diagram with the pieces I intend to use.
In our example, the user will access our API through the API Manager feature in Azure. Using this allows us to consolidate our various Azure Function blocks behind a consistent API name and Url. Further this allows easy definition of rate limiting rules, as well as other elements that while important, will not be in our example.
In our application, the user will upload an image which we will store in blob storage and create a record in our MongoDB instance. The addition of the image to blob storage will trigger another Azure function that is watching for new adds. This function will take the new add and run the image through Azure Cognitive Services which will tell us more about the image. The additional bits of data are then added to the NoSQL document. records from Mongo are transmitted to our user as calls to the GetAll function are made.
For this example, I have chosen to use an Azure Function which means that my method MUST complete in 5 minutes or less or Azure will kill it. Now, the only time that matters is if you are upload a large file or doing a very intensive operation. Though, for the later you would not want to tie that to a web operation anyway, you would favor a form of deferred processing; we actually do that here with our call to Cognitive Services.
In a typical application we often want to consider the type of access a service will require, as it plays into a lot of selection for other components. I chose to use a NoSQL database here because, under normal circumstances for this sort of application, I would expect a lot of usage here but, I dont necessarily care about consistency as much as availability; this is an essential conversation that needs to be had as you plan to build the service.
Finally, I love Azure functions here because they tie so neatly into the existing Azure services. While it would be trivial to write a polling process or, even leverage a Service Bus queue, using Azure functions which can be configured to respond to blob storage adds, means I have less to think about.
Ok, so we have planned our application. Let’s get started by building our Image Upload process in the next section.