PALFINGER cranes with addition of telematic device becoming to be not just useful but also “smart machines”. By providing constant information about machine operation we are able to build additional services to our customers. It is obvious that amount of the data that will be collected through telematic devices will create significante load on our infrastructure. Architecture of the technical solutions that we build needs to be scalable and performant but on the same side costs of the solution should be optimal. Since we are already using Microsoft Azure we decided to use Azure Functions (serverless approach) in order to achieve our requirements.
Azure Functions vs App Service
Information from cranes are coming constantly and all of them first ended up in message queue. Of course not all messages have the same impact and priority. Let’s say that we have 3 priority types: low, normal, high. We are receiving high volume of low and normal priority messages and low volume of high priority messages.
Having situation like explained some of the services would be under constant load while others would be mostly idle. If we would choose App Service and build standard Web Api project we would have coupled services that in case of scaling , scale all services. Of course there comes as well topic of type of scaling (horizontal, vertical) which then also include learning curve to choose proper setup. Of course solution with the App Service would solve the problem but it is not optimal solution and we would be responsible to choose proper setup.
Azure functions gave us features that we wanted. We were able to build functions that would be responsible for processing specific messages and all subject of scaling is per function and Microsoft Azure is responsible for it. In this scenario we were able to focus us to developing features without worrying about infrastructure. With choosing “”Consumption plan” hosting model we are paying for infrastructure only when it is used.
We can say that choosing Azure functions we are locked to the platform since they are only running in Azure, but the code that is hosted inside is properly separated to execution and business logic part. Having said that in case of need to change platform adjustments would be only in the execution part.
In the picture above we can see part of Fleet Monitor solution which include Azure functions. All crane messages are coming to the Service Bus Queue and it is necessary to classify them accordingly. MessageRouter function is triggered on every message that is added to the queue and based on the properties of the message it will be classified and sent to appropriate queue (priority one, priority two) where additional functions will process received messages.
This function is under heavy load constantly and needs to be robust and highly available in order to provide constant flow of data between the crane and our system.
One of the behaviors of the message queues is that the message is deleted from the queue after successful read. In case of any defects on MessageRouter pipeline it would be possible to lose received messages. To prevent that situation one of the first things that we are doing is to copy received message and move to fleet-monitor-logs queue and after that message will be processed by ReadAndSaveLogs function which will save message to Azure Blob storage.
Now we are able to track every message that is sent from the crane and in case of any problems, message can be reprocessed. Probability to lose message with this approach is extremely low.
Azure functions have several trigger types
- Message: listen for a message on a queue
- Http Request: implement WebApi or WebHooks
- Timer: run a function on a schedule
- Many more: Azure Storage Blob creation, SqlServer or CosmosDB new row
In our implementation we have used Message and Timer binding. Function SetEquipmentStatusToOff is time triggered and it was really simple to have it up and running.
In the example above we can see structure of timer the function. We needed to define:
- Name of the function (SetEquipmentStatusToOff)
- Trigger type with configuration (TimerTrigger(“0 0/1 * 1/1 * *”)), cron expression
- Body of the function is business logic
Input setup of MessageRouter looks like below
We can see that MessageRouter have more complex setup then timer function but idea is still the same. We need to define our trigger and bindings in the input parameters of the methods and in the body we will define the correlation. This behavior gave us commodity to not worry about connection and how to subscribe to the changes in the queue.
Is everything that great
In the time of writing this blog Azure Functions are supporting .Net Standard and .net Core version is in the preview status. One of the downsides is that dependency injection by framework is not available (will be in the .net core version). This gave us some limitations with unit testing and we have put more focus on the integration tests.
Since Azure functions support a lot of different triggers and bindings it necessary to mention that every of those have certain details that are different then others and this brings some learning curve.
Microsoft provided great tools for local testing and developing. There was no surprises between run on local development and on Azure. All developers were able really quickly to understand and use Azure functions. We were able to focus on developing business features which gave us some speed in product development. Key part of processing crane messages was able to be enough performant and resilient to fulfill our standards.
With all this benefits we can say that we didn’t regret for choosing Azure Functions to be part of our solution.