Skip to main content

Azure Functions

·1079 words·6 mins
Azure Functions Serverless

When it comes to serverless offerings Azure Functions can at first seem like a breath of fresh air. But is everything as it seems?

What are Azure Functions?
#

If you come from an Amazon Web Services (AWS) background you might be familiar with their serverless functions offering called Lambda. In the Azure world they have a more down-to-earth name1 for a similar concept: Azure Functions. Serverless functions simply mean that you provide your code in the form of a function that will be triggered due to an external event of some kind.

The good stuff
#

Azure Functions has a few nice features compared to AWS Lambda2.

  • Input and output bindings: This is the most powerful concept in the Azure Function service. An input binding represents a way to get additional data into your function before your function logic even starts executing. This could for instance be fetching data from a database or fetching a blob from blob storage. An output binding represents a way to output data from your function without handling all the details with SDKs and clients to achieve this. This could for instance be posting a message to a Service Bus queue or adding documents to a NoSQL database. All kinds of bindings take place behind the scenes, all you have to do is to configure the binding in a JSON file. For instance, using an input binding to fetch a number of documents from a Cosmos DB could look like the following
    {
        "name": "blogPost",
        "type": "cosmosDB",
        "direction": "in",
        "databaseName": "MyDatabase",
        "collectionName": "MyCollection",
        "sqlQuery": "SELECT * FROM c WHERE c.blogPostId = {blogPostId}",
        "connectionStringSetting": "CosmosDBConnection"
    }
    
  • Sharing code between functions: Have you tried using Lambda layers in AWS? I did it once, and I have no desire to ever use it again. An Azure Function app is a logical grouping of functions where they can share code exactly like they were part of the same application. If you have several functions that should act like one application, then you put them in the same project and they can share any code they want and they are deployed together. I know something similar could be achieved with AWS Lambda, but all the ways I have seen are hacks and you usually end up having a bunch of separate functions that all have the exact same code but each function only uses 10% of that code (and it is a bad practice to make your functions larger than they need to be).
  • Triggers: up until recently there was no way to directly trigger a Lambda function via an HTTP request, so you had to set up additional resources (an API Gateway or an Application Load Balancer) to achieve this. But to be fair, you can no do that without the additional resources. However, Azure Functions had this feature from the start and it is very easy to use. A trigger is defined in the same JSON document as all the input and output bindings. A matching HTTP trigger to the Cosmos DB input binding defined above could be the following, where the {blogPostId} variable is bound to the value passed in the HTTP request (and it is then used in the database query)
    {
        "type": "httpTrigger",
        "name": "request",
        "direction": "in",
        "methods": [ "get" ],
        "route": "posts/{blogPostId}"
    }
    

The bad stuff
#

Great, we have seen all the good stuff that Azure Functions bring - now on to the bad stuff. To be honest, most of these bad stuff are things you might not encounter in every situation.

  • Network integration: you want to put your Azure Functions in a virtual network? This opens the Pandora’s box of problems. I will not even begin to describe what it will take to do this, just know that it is not as trivial as one expects it to be.
  • Linux: one odd thing about Azure Functions is that you have to select if you want your functions to run on Linux or on Windows. Why? This is a mystery. Depending on what you choose you will have different options of what language runtime you can select. For instance, Python requires Linux. That might not sound so bad at first, just strange. But there are issues with the Linux version. The biggest issue3 is that you will discover that it is not possible (or at least very difficult) to do both of these things: (1) set up a complete Azure Functions app running Linux together with all the environment variables the application needs using Bicep, and (2) deploy code via a pipeline of some sort. Why is this? The reason is technical and has to do with where the source code to your functions is stored and how the Azure Function resource has access to this code. I will need a whole separate blog post to explain how this works.
  • Serverless with servers: The level of abstraction around the servers in an Azure Function resource is terrible. There is a place where you can slide a counter and set the number of servers you wish your app to be able to scale to. The maximum number is 200, by the way.
  • When serverless is not enough: All of what I have said so far has really been about the “consumption” pricing model of Azure Functions. There are other pricing models. But then you are not really using serverless, and you will find that it quickly gets very pricy.
  • Infrastructure as code: Setting up Azure Functions via Bicep for the first time is difficult. The names of the resources does not make sense. The properties that you need to set to create a Linux Function App are impossible to guess. The Azure provider for Terraform has at least tried to make this a bit easier, so maybe go look into that if you want to set up Azure Functions using infrastructure as code.

Summary
#

If I could give the Azure Functions team praise it would be for the amazing input and output bindings feature. If I can give them advice on what to do better it would be to increase the level of abstraction. I don’t want to know if I run Windows or Linux. I don’t want to know how many server instances are running.


  1. To be fair, if you are familiar with functional programming and Lambda calculus this naming will seem pretty reasonable. ↩︎

  2. That is, according to me. If you don’t agree that is fine. ↩︎

  3. Again, according to me. ↩︎

Mattias Fjellström
Author
Mattias Fjellström
Cloud architect consultant and an HashiCorp Ambassador