Adding Health Checks to your Azure Functions

Out of the box Azure Functions do not offer a way to monitor the health of your service. See how to easily add dependency health checks to your functions.

Adding Health Checks to your Azure Functions

Out of the box ASP.NET Core offers health check middleware and libraries for your ASP.NET websites and API's. These health check probes are exposed as HTTP endpoints so they can be monitored by an external service such as Azure Monitor. Health checks can be used by container orchestrators and load balancers to verify the status of your service. They can also verify the use of memory, disk, and other physical resources to check the health of the server.

Well if that's the case, why monitor serverless Azure Functions? After all, isn't the beauty of serverless computing that you do not have to manage your servers? The answer is that health checks can test your functions underlying dependencies such as databases and other external services to confirm the availability of your functions.

Personally I have create many Azure Functions that have numerous integrations points that can become points of failure during deployments into higher environments. I have worked on clients that have 5 distinct environments that require the external dependencies to be deployed and also configured for each environment.

During my initial research I found a fantastic set of pre-built health checks called AspNetCore.Diagnostics.HealthChecks. These health checks can be integrated into the diagnostics health check middleware available in ASP.NET core. The problem with trying to leverage this feature out of the box is it's not compatible with Azure Functions. When I dug into the code, I noticed it was because of an extension method that registered a hosted service named HealthCheckPublisherHostedService.

In order to get around this limitation I created the Azure Function Health library that simulates everything the ASP.NET Core diagnostics library does, except register the HealthCheckPublisherHostedService class. It turns out this worked perfectly for my needs.

How To Use It

In the GitHub repository I created for this application, it includes a sample Azure Function application that demonstrates how to use the library and setup a simple SQL Database health check probe. Here are some overall steps to add this to your project:

  1. Add the following Nuget package to your Azure Function Project: Microsoft.Extensions.Diagnostics.HealthChecks
  2. Add a Nuget package for the health check you would like to add: i.e. AspNetCore.HealthChecks.SqlServer
  3. Add a reference to the FunctionHealthCheck project listed in this repository
  4. Include a Startup class to register the specific health checks required for your project. This will allow you to setup dependency injection.
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Function.HealthCheck.SQL;
using FunctionHealthCheck;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using System;

[assembly: FunctionsStartup(typeof(Startup))]
namespace Function.HealthCheck.SQL
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            ConfigureServices(builder.Services);
        }

        public void ConfigureServices(IServiceCollection services)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            services.AddLogging();

            services.AddFunctionHealthChecks()
                .AddSqlServer(
                  connectionString: "Server=localhost;Database=yourdb;User Id=app;Password=test123");

        }
    }
}

5. Add a health check endpoint for your application to expose:

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Microsoft.Extensions.Diagnostics.HealthChecks;

namespace Function.HealthCheck.SQL
{
    public class HttpFunc
    {
        private readonly HealthCheckService _healthCheck;
        public HttpFunc(HealthCheckService healthCheck)
        {
            _healthCheck = healthCheck;
        }

        [FunctionName("Heartbeat")]
        public async Task<IActionResult> Heartbeat(
           [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "heartbeat")] HttpRequest req,
           ILogger log)
        {
            log.Log(LogLevel.Information, "Received heartbeat request");

            var status = await _healthCheck.CheckHealthAsync();

            return new OkObjectResult(Enum.GetName(typeof(HealthStatus), status.Status));
        }

    }
}

6. Setup an external monitoring tool like Azure Monitor to create a ping test against this endpoint.

As a reminder, remember that while the sample is limited to setting up a health check for SQL Server, the AspNetCore.Diagnostics.HealthChecks has a number of additional health checks you can use in your application by just adding the related package and configuring the check in the startup class.

Adding these health checks can be a simple way to verify the health of your services and can be extremely helpful when diagnosing issues in higher environments. When used in tandem with a monitoring solution like Azure Monitor, you will be notified as soon as your Functions experience issues and can provide you with the insight you need to resolve the issue.