Swimburger

Introducing Umbraco's KeepAlive Ping configuration

Niels Swimberghe

Niels Swimberghe - - Umbraco

Follow me on Twitter, buy me a coffee

Umbraco logo next to text: Introducing Umbraco's KeepAlive configuration

With the release of Umbraco 8.6.0, there's now a way to configure the built-in KeepAlive behavior (pull request #7164). The new keepAlive node can be found inside of umbracoSettings.config which has two attributes:

  • keepAlivePingUrl: Change the URL pinged to keep the Umbraco instance alive. Defaults to "{umbracoApplicationUrl}/api/keepalive/ping".
  • disableKeepAliveTask: Disable the KeepAlive time interval task by setting it to true. Default to false.

Here's what the configuration looks like by out of the box:

<?xml version="1.0" encoding="utf-8" ?>
<settings>
  ...
  <!--
  keepAlive
    @disableKeepAliveTask
      Disables the periodic KeepAliveTask when set to "true".
      Use this setting to disable the KeepAliveTask in case you already have an alternative.
      For example, Azure App Service has keep alive functionality built-in.
      Defaults to "false".
    @keepAlivePingUrl
      The url of the KeepAlivePing action. By default, the url will use the umbracoApplicationUrl setting as the basis.
      Change this setting to specify an alternative url to reach the KeepAlivePing action. eg http://localhost/umbraco/api/keepalive/ping
      Defaults to "{umbracoApplicationUrl}/api/keepalive/ping".
  -->
  <keepAlive disableKeepAliveTask="false" keepAlivePingUrl="{umbracoApplicationUrl}/api/keepalive/ping" />
</settings>

The new configurations help you solve the following two issues:

1. KeepAlive doesn't work due to incorrect URL (404) #

Problem #

This is how the KeepAlive functionality works with the default configuration:

  1. If the UmbracoApplicationUrl isn't explicitly configured, the first requests made to Umbraco will populate the UmbracoApplicationUrl with whichever FQDN URL was used to make that request. 
  2. On a timed schedule, the ApplicationUrl is used as the base URL to ping the KeepAlive controller. The URL looks like this: {umbracoApplicationUrl}/api/keepalive/ping
  3. The OnlyLocalRequests attribute verifies if the request to the KeepAliveController.Ping action came from the local machine.
    If the request is not made from the local machine, Umbraco returns HTTP 404 response.
  4. The KeepAliveController.Ping action receives the request and returns this XML:
    <KeepAlivePingResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Umbraco.Web.Editors">
        <Message>I'm alive!</Message>
        <Success>true</Success>
    </KeepAlivePingResult>
    

This is a straightforward process, but there's no guarantee that the URL to ping will resolve to the local machine as required by the OnlyLocalRequests attribute. What if the ApplicationUrl resolves to a public domain name A but the requests are load balanced among two servers with private domain names B & C?

  1. UmbracoApplicationUrl will hold https://domain-A.tld/umbraco
  2. The KeepAlive timer job will ping https://domain-A.tld/umbraco/api/keepalive/ping
  3. domain-A.tld will resolve to the public IP of the load balancer which is where the HTTP request will be send to.
  4. The OnlyLocalRequests attribute will reject the HTTP request and return an HTTP 404 response
  5. The KeepAlive job will log the 404 response

Note 1: even though the log will be filled with 404 errors, the KeepAlive functionality still 'kinda' works. Any HTTP request made to the Umbraco instance or any ASP.NET website on a regular basis will keep it alive.
Note 2: most load balancers already have built-in health checks which will check whether the website is up and running using HTTP Requests. These requests also would keep the websites alive making the KeepAlive functionality redundant.

When using self-hosted IIS web servers, you could easily resolve these issues by adding internal DNS records that would make the public domain resolve to localhost. But many hosting platforms do not provide the same level of control and customization. This is the case for Azure App Services which would run into the exact same issue as described above, except you can't even request localhost 80 or 443 in an app service.

Solution #

With the new keepAlive configuration, you can configure which URL to ping using the keepAlivePingUrl attribute on the keepAlive node in the umbracoSettings.config file.
In case of the load balancing scenario, you should configure the keepAlivePingUrl with the correct internal domain name that resolves to localhost, or you could simply use localhost if your IIS bindings support that:

<?xml version="1.0" encoding="utf-8" ?>
<settings>
  ...
  <!--
  keepAlive
    @disableKeepAliveTask
      Disables the periodic KeepAliveTask when set to "true".
      Use this setting to disable the KeepAliveTask in case you already have an alternative.
      For example, Azure App Service has keep alive functionality built-in.
      Defaults to "false".
    @keepAlivePingUrl
      The url of the KeepAlivePing action. By default, the url will use the umbracoApplicationUrl setting as the basis.
      Change this setting to specify an alternative url to reach the KeepAlivePing action. eg http://localhost/umbraco/api/keepalive/ping
      Defaults to "{umbracoApplicationUrl}/api/keepalive/ping".
  -->
  <!-- For Web Server A -->
  <keepAlive disableKeepAliveTask="false" keepAlivePingUrl="https://[INTERNAL_DOMAIN_NAME_A]/api/keepalive/ping" />
</settings>

Unfortunately, specifying localhost for Umbraco instances hosted on Azure App Services will not work. Azure App Services won't allow you to request localhost 80 or 443. Luckily, Azure App Service already has its own alternative KeepAlive functionality.

2. Redundant KeepAlive functionality #

Many platforms already provide their own KeepAlive behavior such as Azure App Services, many load balancers, and reverse proxies. One of the new configuration options allows you to disable Umbraco's KeepAlive functionality. To disable the KeepAlive functionality, change the disableKeepAliveTask from false to true.

<?xml version="1.0" encoding="utf-8" ?>
<settings>
  ...
  <!--
  keepAlive
    @disableKeepAliveTask
      Disables the periodic KeepAliveTask when set to "true".
      Use this setting to disable the KeepAliveTask in case you already have an alternative.
      For example, Azure App Service has keep alive functionality built-in.
      Defaults to "false".
    @keepAlivePingUrl
      The url of the KeepAlivePing action. By default, the url will use the umbracoApplicationUrl setting as the basis.
      Change this setting to specify an alternative url to reach the KeepAlivePing action. eg http://localhost/umbraco/api/keepalive/ping
      Defaults to "{umbracoApplicationUrl}/api/keepalive/ping".
  -->
  <!-- For Web Server A -->
  <keepAlive disableKeepAliveTask="true" />
</settings>

Now that Umbraco's KeepAlive task is disabled, make sure your alternative is enabled. For Azure App Service, enable "Always On" in the General Settings of your app service.

TL;DR #

Umbraco 8.6 introduces the new keepAlive configuration inside of umbracoSettings.config which allows you to change these two attributes:

  • keepAlivePingUrl: Change the URL pinged to keep the Umbraco instance alive. Defaults to "{umbracoApplicationUrl}/api/keepalive/ping".
  • disableKeepAliveTask: Disable the KeepAlive time interval task by setting it to true. Default to false.

Related Posts

Related Posts