Re: Appropriate use of HTTP status codes for application health checks

Willy Tarreau <> Mon, 27 February 2017 06:23 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 41D521296C3 for <>; Sun, 26 Feb 2017 22:23:38 -0800 (PST)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -6.922
X-Spam-Status: No, score=-6.922 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, HEADER_FROM_DIFFERENT_DOMAINS=0.001, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id z9ycwSSdOpLm for <>; Sun, 26 Feb 2017 22:23:36 -0800 (PST)
Received: from ( []) (using TLSv1.2 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) by (Postfix) with ESMTPS id C7661129665 for <>; Sun, 26 Feb 2017 22:23:36 -0800 (PST)
Received: from lists by with local (Exim 4.80) (envelope-from <>) id 1ciEg3-0004iM-HZ for; Mon, 27 Feb 2017 06:20:55 +0000
Resent-Date: Mon, 27 Feb 2017 06:20:55 +0000
Resent-Message-Id: <>
Received: from ([]) by with esmtps (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from <>) id 1ciEfw-0004gn-4K for; Mon, 27 Feb 2017 06:20:48 +0000
Received: from ([] by with esmtp (Exim 4.84_2) (envelope-from <>) id 1ciEfo-0002LU-5w for; Mon, 27 Feb 2017 06:20:42 +0000
Received: (from willy@localhost) by pcw.home.local (8.15.2/8.15.2/Submit) id v1R6JbD0005805; Mon, 27 Feb 2017 07:19:37 +0100
Date: Mon, 27 Feb 2017 07:19:37 +0100
From: Willy Tarreau <>
To: Amos Jeffries <>
Message-ID: <>
References: <> <> <> <>
MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: inline
In-Reply-To: <>
User-Agent: Mutt/1.6.1 (2016-04-27)
Received-SPF: pass client-ip=;;
X-W3C-Hub-Spam-Status: No, score=-7.0
X-W3C-Hub-Spam-Report: AWL=0.943, BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, W3C_AA=-1, W3C_IRA=-1, W3C_IRR=-3, W3C_WL=-1
X-W3C-Scan-Sig: 1ciEfo-0002LU-5w d38e67d2dec64cfaf2f107f5dc75751a
Subject: Re: Appropriate use of HTTP status codes for application health checks
Archived-At: <>
X-Mailing-List: <> archive/latest/33621
Precedence: list
List-Id: <>
List-Help: <>
List-Post: <>
List-Unsubscribe: <>

On Mon, Feb 27, 2017 at 05:38:49PM +1300, Amos Jeffries wrote:
> On 23/02/2017 11:24 p.m., Willy Tarreau wrote:
> > Hi Amos,
> > 
> > On Thu, Feb 23, 2017 at 10:53:07PM +1300, Amos Jeffries wrote:
> >> IMHO a better efficient way for a polling system is to use 204 as "All
> >> okay", and 200 as "some problem(s)". No bandwidth wasted with payload on
> >> the common Up status, and ability to deliver details about the outage on
> >> the Down status.
> > 
> > In fact it's common to see health check applications return 5xx for a
> > very simple reason, the front equipment performing the check (often a
> > load balancer) has to deal with these situations anyway, and most use
> > cases just want to return "completely up" or "completely dead". But I
> > agree that when you want to support the gray area in between, it's much
> > better to support intermediary codes. FWIW haproxy also supports a
> > special case of 404 to mean "closing soon, no more requests please" so
> > that admins can simply touch/rm a file in a docroot. That's just to say
> > that there are many valid use cases and tha common sense adapted to what
> > components *reliably* support is often the best here.
> > 
> For an individual health-check you are right. But that is not the
> use-case matt has.
> The use-case in question is for the response coming from some aggregator
> process, which uses health-checks as its input/data. One status code
> summarizing the situation of N endpoints.  No 4xx or 5xx is going to be
> adequate for that, simply because of what the 400 and 500 defaults mean
> to the general HTTP ecosystem.

I totally get your point but I see a big difference between what would
be perfect and what components can do. For example for over a decade
haproxy was not able to consider anything but a status code, and because
of this there have been many people who implemented 500 as a response to
aggregated tests just for this (now it's more flexible). And I've had to
deal with other products which could only use this as well.

Also, even for an aggregated test, you may end up with real 5xx errors
because of timeouts or failure to deal with unexpected responses, so
the LB still has to deal with this case normally.

So I'd summarize it like this when seen from the front component :

   - 200 => status is OK
   - <something> => status is faulty (partially or totally)
   - 5xx => a technical error appeared during the processing

Given the 5xx has to be dealt with, if there is no need for a clear
distinction between a failure in the health check component and a
faulty test, the 5xx will work fine. If it's needed to make a
distinction (eg: all responses are logged), then something else
would be better (including some 2xx as you proposed).