Check Redis connectivity inside heartbeat.aspx health check

Getting your health check right is important when designing a highly available and elastic Sitecore solution. For years Sitecore comes with an builtin health check page at /sitecore/service/heartbeat.aspx which checks the status of the the SQL databases. This can be used for a load balancer or docker health check. A few quick notes on the heartbeat.aspx:

  • In some versions of Sitecore the heartbeat.aspx will throw an error, and you will have to exclude some connection strings from it as described in a different article on this blog
  • Starting in Sitecore 9.3 a new health check mechanism is used based on the Microsoft.Extensions.Diagnostics.HealthChecks namespace. Here is a great article describing how to customize this. The same code from below can be used in the updated health check mechanism.

There are several different approaches when setting up a health check in Sitecore. In most cases I recommend keeping the health check small to prevent it from going unhealthy during heavy load, this technique can be combined with the Application Initialization feature in IIS to warmup the solution after the site starts.

The code for the heartbeat.aspx lives in Sitecore.Web.Services.HeartbeatCode in the Sitecore.Client assembly. The important methods are virtual so they can be overriden to implement additional checks to ensure all critical components of the solutions are healthy.

There are many Sitecore solutions where the private session state is stored in Redis and its availability is critical. In such scenarios it will make sense to ping Redis from the health check to ensure the server can access it. Below code sample shows how to check the Redis database which is setup for private session state:

public class CustomHeartbeat : Sitecore.Web.Services.HeartbeatCode
{
    protected BeatResults CheckRedis(BeatResults beatresult)
    {
        //get connection details for private Redis session database
        //same pattern can be used to check shared session database
        var sessionSection = (SessionStateSection)WebConfigurationManager.GetSection("system.web/sessionState");
        var connString = sessionSection.Providers["Redis"].Parameters.Get("connectionString");
        string redisConnection = ConfigurationManager.ConnectionStrings[connString].ConnectionString;

        using (ConnectionMultiplexer connection = ConnectionMultiplexer.Connect(redisConnection))
        {
            var subscriber = connection.GetSubscriber();
            var timespan = subscriber.Ping();

            Log.Info($"Successfully pinged Redis from healthcheck in: {timespan}", this);
        }

        return beatresult;
    }

    protected override BeatResults DoBeat()
    {
        //this checks the SQL databases
        var beatResults = base.DoBeat();

        beatResults = CheckRedis(beatResults);

        return beatResults;
    }
}
Advertisement