1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-08 15:02:10 +03:00

Allow for a simple socket check in addition to the

higher level protocol-level checks for backends...

Not sure if it makes sense to do both or not... Comments?

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1516930 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jim Jagielski
2013-08-23 16:48:42 +00:00
parent 66eaba96f6
commit 357828f9d2
6 changed files with 56 additions and 22 deletions

View File

@@ -1003,7 +1003,9 @@ ProxyPass /mirror/foo http://backend.example.com
<tr><td>ping</td>
<td>0</td>
<td>Ping property tells the webserver to "test" the connection to
the backend before forwarding the request. For AJP, it causes
the backend before forwarding the request. For negative values
the test is a simple socket check, for positive values it's
a more functional check, dependent upon the protocol. For AJP, it causes
<module>mod_proxy_ajp</module>to send a <code>CPING</code>
request on the ajp13 connection (implemented on Tomcat 3.3.2+, 4.1.28+
and 5.0.13+). For HTTP, it causes <module>mod_proxy_http</module>

View File

@@ -233,7 +233,7 @@ static const char *set_worker_param(apr_pool_t *p,
*/
if (ap_timeout_parameter_parse(val, &timeout, "s") != APR_SUCCESS)
return "Ping/Pong timeout has wrong format";
if (timeout < 1000)
if (timeout < 1000 && timeout >= 0)
return "Ping/Pong timeout must be at least one millisecond";
worker->s->ping_timeout = timeout;
worker->s->ping_timeout_set = 1;

View File

@@ -972,6 +972,13 @@ PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc,
APR_DECLARE_OPTIONAL_FN(int, ap_proxy_clear_connection,
(request_rec *r, apr_table_t *headers));
/**
* @param socket socket to test
* @return TRUE if socket is connected/active
*/
PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *socket);
#define PROXY_LBMETHOD "proxylbmethod"
/* The number of dynamic workers that can be added when reconfiguring.

View File

@@ -759,22 +759,35 @@ static int proxy_ajp_handler(request_rec *r, proxy_worker *worker,
/* Handle CPING/CPONG */
if (worker->s->ping_timeout_set) {
status = ajp_handle_cping_cpong(backend->sock, r,
worker->s->ping_timeout);
/*
* In case the CPING / CPONG failed for the first time we might be
* just out of luck and got a faulty backend connection, but the
* backend might be healthy nevertheless. So ensure that the backend
* TCP connection gets closed and try it once again.
*/
if (status != APR_SUCCESS) {
backend->close = 1;
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00897)
"cping/cpong failed to %pI (%s)",
worker->cp->addr, worker->s->hostname);
status = HTTP_SERVICE_UNAVAILABLE;
retry++;
continue;
if (worker->s->ping_timeout_set < 0) {
if (!ap_proxy_is_socket_connected(backend->sock)) {
backend->close = 1;
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO()
"socket check failed to %pI (%s)",
worker->cp->addr, worker->s->hostname);
status = HTTP_SERVICE_UNAVAILABLE;
retry++;
continue;
}
}
else {
status = ajp_handle_cping_cpong(backend->sock, r,
worker->s->ping_timeout);
/*
* In case the CPING / CPONG failed for the first time we might be
* just out of luck and got a faulty backend connection, but the
* backend might be healthy nevertheless. So ensure that the backend
* TCP connection gets closed and try it once again.
*/
if (status != APR_SUCCESS) {
backend->close = 1;
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00897)
"cping/cpong failed to %pI (%s)",
worker->cp->addr, worker->s->hostname);
status = HTTP_SERVICE_UNAVAILABLE;
retry++;
continue;
}
}
}
/* Step Three: Process the Request */

View File

@@ -1975,13 +1975,25 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
}
}
/* Step Three-and-a-Half: See if the socket is still connected (if desired) */
if (worker->s->ping_timeout_set && worker->s->ping_timeout < 0 &&
!ap_proxy_is_socket_connected(backend->sock)) {
backend->close = 1;
ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r, APLOGNO()
"socket check failed to %pI (%s)",
worker->cp->addr, worker->s->hostname);
retry++;
continue;
}
/* Step Four: Send the Request
* On the off-chance that we forced a 100-Continue as a
* kinda HTTP ping test, allow for retries
*/
if ((status = ap_proxy_http_request(p, r, backend, worker,
conf, uri, locurl, server_portstr)) != OK) {
if ((status == HTTP_SERVICE_UNAVAILABLE) && worker->s->ping_timeout_set) {
if ((status == HTTP_SERVICE_UNAVAILABLE) && worker->s->ping_timeout_set &&
worker->s->ping_timeout > 0) {
backend->close = 1;
ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r, APLOGNO(01115)
"HTTP: 100-Continue failed to %pI (%s)",

View File

@@ -2245,7 +2245,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
#endif
#if USE_ALTERNATE_IS_CONNECTED && defined(APR_MSG_PEEK)
static int is_socket_connected(apr_socket_t *socket)
PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *socket)
{
apr_pollfd_t pfds[1];
apr_status_t status;
@@ -2283,7 +2283,7 @@ static int is_socket_connected(apr_socket_t *socket)
}
#else
static int is_socket_connected(apr_socket_t *sock)
PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *socket)
{
apr_size_t buffer_len = 1;
@@ -2466,7 +2466,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
if (conn->sock) {
if (!(connected = is_socket_connected(conn->sock))) {
if (!(connected = ap_proxy_is_socket_connected(conn->sock))) {
socket_cleanup(conn);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00951)
"%s: backend socket is disconnected.",