Azure functions implementation and best practices
The benefits of using Azure Functions in your applications are manifold. It is serverless, helps you to simplify development, and even seamlessly integrates with other Azure services to make your life as a developer much simpler.
These benefits were demonstrated through a few practical examples in our previous post. In this post, we are going to take you one step ahead by helping you understand how to implement Azure Functions using one of those practical examples. So in case you haven’t read our previous post, have a quick look at it before proceeding with this post.
We are also going to talk about some of the best practices for Azure Functions that you can follow to successfully implement in your next Azure Functions.
Creating your own Azure Functions
To jog your memory, one of the practical examples we had discussed in our previous post was about an application where the users need to upload the college grade sheet in ZIP format. To validate the authenticity of those grade sheets, the files had to be unzipped and processed sequentially. And to achieve this, we are going to create an Azure Functions that will be triggered once the zipped files are uploaded in blob storage. It will then perform the unzipping and transfer the unzipped files to another blob storage for the application to pick it up.
- Prerequisite
The latest version of Microsoft Visual Studio with required plugins for Azure installed in it.
Steps
- Step 1: Choose the ‘Azure Function’ template as the project template while creating a new project in your Microsoft Visual Studio.
- Step 2: Provide a valid name for the Azure Functions. In this case, we have named the function as PracticeFunctionApp.
- Step 3: Choose the type of trigger (Blob trigger in our case) by which the Azure Functions can be triggered.
- Step 4: once this is created, check out the solution explorer which will look like the below.
- Step 5: Open the Function1.cs file which will have a method called ‘Run’ already defined. This will get the blob file and its name from the trigger.
- Step 6: Update the Run method to make it perform the required functionality. (Read the compressed file that is triggered and unzip it. Then place the uncompressed file(s) in another blob storage).
The below code logs the file name once the function is triggered. It proceeds to validate whether the file extension is ‘zip’ (ensuring it is validating the input). It uses the in-built class ZipArchive to uncompress the files. After uncompressing the file, it connects to the destination container and uploads the individual files.
Reference code
if (Path.GetExtension(name) == “zip”)
{
var archive = new ZipArchive(myBlob);
var destStorageAccount = CloudStorageAccount.Parse(Environment.GetEnvrionmentVariable(“destinationStorage”));
var blobClient = destStorageAccount.CreateCloudBlobClient();
var destStorageContainer = blobClient.GetContainerReference(Environment.GetEnvrionmentVariable(“destinationContainer”));
foreach (var entry in archive.Entries)
{
var blockBlob = destStorageContainer.GetBlockBlobReference(entry.FullName);
using var filestream = entry.Open();
blockBlob.UploadFromStreamAysnc(filestream);
}
}
Copy
Best practices for Azure Functions
Now that you have seen how to implement Azure Functions, let us understand some of the best practices that can be followed while designing and creating Azure Functions.
- Short running functions
Create Functions that run for a short time and design them to handle lighter operations. This will avoid the unexpected timeout exceptions and unfinished operations.
A characteristic that defines short-running functions is the absence of any large dependencies. Create a series of functions, each of them holding small pieces of codes and unique operations leading to faster operation time. This will also help in reusability.
- Have a medium to pass information
The series of functions that you create should not communicate with each other directly, rather it should communicate through storage queues.
Storage queues can act as a medium between the functions. In this, the output of one function will be dropped in the storage queues which in turn becomes the input for another function. Similarly, Service Bus can also be used as a medium.
- Validate inputs
Since the functions can be triggered through multiple options (Cloud storage (Blob), NoSQL database (CosmosDB), Event Hubs, Queue, Http, etc.) there is always a possibility of passing an invalid input and exploiting the code. So, it is always wise to validate the input that is passed to the function.
- Ability to process identical inputs
Since functions are event-driven, there is a possibility of firing an event that can occur more than once due to environment or human errors. So, ensure that the function is designed in a way that it validates the functionality of the operation before it starts executing it.
For example, assume a function that has been written to delete a certain entry from the database. Due to some system issues, if this function was triggered multiple times, it can turn into a catastrophe. To avoid this, ensure that the function can handle it.
- Make functions stateless
Stateless applications are those that typically do not save information generated in one session and pass it on to the next session for processing. Functions have to be designed stateless so that it can process the same input the same way for any number of times.
In case if there is a dependency to maintain the state, then the information can be stored and retrieved from SQL database or file storage.
- Secure the secrets used in the function
In some cases, you would be required to connect to databases, APIs, or some systems to manage sensitive configuration information from the functions.
Storing such secrets directly in the config file can be quite dangerous as the chances of this information falling into the wrong hands are high, especially since it is stored in the code repositories. In such scenarios, Azure Key Vault can be used to store the secrets.
- Build asynchronous code
Asynchronous programming is always recommended especially when blocking input and output operations are involved.
For example, let us assume that there is an API call in the function, which would block a couple of seconds while executing the function and disable us to proceed to execute the codes that are present further down. In such cases, asynchronous programming would be helpful as it will enable us to proceed further while it calls and gets the response from the API.
- Have separate function apps for different regions
Functions that are deployed under the same function app share the same resources (eg - memory). So, avoid creating functions of different regions (i.e development, testing, and production) under the same function app.
Similarly, functions apps are associated with storage accounts. To enhance the performance of the functions, have a separate storage account for each function app.
- Assign only required permissions
Functions apps should have only the essential privileges which are required for the successful execution of its task. Functions having privileges to access unessential features would open up a chance to have a security catastrophe in the organization’s cloud.
To avoid such incidents, Azure Role-Based Access Control can be used to assign essential privileges.
- Log the activities
Write the function code in such a way that the important operations and failure events are logged, so that it comes in handy when the desired results are not obtained after the execution of the function. Turning on ‘Application Insights’ for azure functions will help in capturing the logs.
- Have security features
Deploying Azure Functions with a storage account in a public cloud exposes the Azure Functions’ endpoint on the internet. If the endpoints are not authenticated properly, it creates the risk of having anyone consuming or misusing the functions. So, it is necessary to implement authentication and authorization features in Azure Functions by implementing OAuth2 or security tokens.
Wrapping up
In this post, we have seen how to implement your own Azure Functions and also some of the best practices to follow while handling it. Always remember that even though Azure Functions is serverless, there are areas where we need to take caution while implementing it. This article will clearly help you in building a robust, scalable, and secure system and help deliver value to your customers.