|
|
|
@ -636,16 +636,43 @@ static void fcgi_proc_set_state(fcgi_extension_host *host, fcgi_proc *proc, int
|
|
|
|
|
proc->state = state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fcgi_proc_disable(server *srv, fcgi_extension_host *host, fcgi_proc *proc, handler_ctx *hctx) {
|
|
|
|
|
if (host->disable_time || (proc->is_local && proc->pid == hctx->pid)) {
|
|
|
|
|
proc->disabled_until = srv->cur_ts + host->disable_time;
|
|
|
|
|
fcgi_proc_set_state(host, proc, proc->is_local ? PROC_STATE_DIED_WAIT_FOR_PID : PROC_STATE_DIED);
|
|
|
|
|
|
|
|
|
|
if (hctx->conf.debug) {
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sds",
|
|
|
|
|
"backend disabled for", host->disable_time, "seconds");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static void fcgi_proc_connect_error(server *srv, fcgi_extension_host *host, fcgi_proc *proc, handler_ctx *hctx, int errnum) {
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sssb",
|
|
|
|
|
"establishing connection failed:", strerror(errnum),
|
|
|
|
|
"socket:", proc->connection_name);
|
|
|
|
|
|
|
|
|
|
if (host->disable_time || (proc->is_local && proc->pid == hctx->pid)) {
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sdssdsd",
|
|
|
|
|
"backend error; we'll disable it for", host->disable_time,
|
|
|
|
|
"seconds and send the request to another backend instead:",
|
|
|
|
|
"reconnects:", hctx->reconnects,
|
|
|
|
|
"load:", host->load);
|
|
|
|
|
proc->disabled_until = srv->cur_ts + host->disable_time;
|
|
|
|
|
if (EAGAIN == errnum) {
|
|
|
|
|
/* - EAGAIN: cool down the backend; it is overloaded */
|
|
|
|
|
if (hctx->conf.debug) {
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbsd",
|
|
|
|
|
"This means that you have more incoming requests than your FastCGI backend can handle in parallel."
|
|
|
|
|
"It might help to spawn more FastCGI backends or PHP children; if not, decrease server.max-connections."
|
|
|
|
|
"The load for this FastCGI backend", proc->connection_name, "is", proc->load);
|
|
|
|
|
}
|
|
|
|
|
fcgi_proc_set_state(host, proc, PROC_STATE_OVERLOADED);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* we got a hard error from the backend like
|
|
|
|
|
* - ECONNREFUSED for tcp-ip sockets
|
|
|
|
|
* - ENOENT for unix-domain-sockets
|
|
|
|
|
*/
|
|
|
|
|
fcgi_proc_set_state(host, proc, proc->is_local ? PROC_STATE_DIED_WAIT_FOR_PID : PROC_STATE_DIED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (EAGAIN == errnum) {
|
|
|
|
|
fcgi_proc_tag_inc(srv, hctx, CONST_STR_LEN(".overloaded"));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
fcgi_proc_tag_inc(srv, hctx, CONST_STR_LEN(".died"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fcgi_proc_check_enable(server *srv, fcgi_extension_host *host, fcgi_proc *proc) {
|
|
|
|
@ -1668,14 +1695,7 @@ static int fcgi_header(FCGI_Header * header, unsigned char type, int request_id,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
|
CONNECTION_OK,
|
|
|
|
|
CONNECTION_DELAYED, /* retry after event, take same host */
|
|
|
|
|
CONNECTION_OVERLOADED, /* disable for 1 second, take another backend */
|
|
|
|
|
CONNECTION_DEAD /* disable for 60 seconds, take another backend */
|
|
|
|
|
} connection_result_t;
|
|
|
|
|
|
|
|
|
|
static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *hctx) {
|
|
|
|
|
static int fcgi_establish_connection(server *srv, handler_ctx *hctx) {
|
|
|
|
|
sock_addr addr;
|
|
|
|
|
struct sockaddr *fcgi_addr = (struct sockaddr *)&addr;
|
|
|
|
|
socklen_t servlen;
|
|
|
|
@ -1686,11 +1706,13 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
|
|
|
|
|
|
|
|
|
|
if (!buffer_string_is_empty(proc->unixsocket)) {
|
|
|
|
|
if (1 != sock_addr_from_str_hints(srv, &addr, &servlen, proc->unixsocket->ptr, AF_UNIX, 0)) {
|
|
|
|
|
return CONNECTION_DEAD;
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (1 != sock_addr_from_buffer_hints_numeric(srv, &addr, &servlen, host->host, host->family, proc->port)) {
|
|
|
|
|
return CONNECTION_DEAD;
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1723,23 +1745,10 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
|
|
|
|
|
"connect delayed; will continue later:", proc->connection_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CONNECTION_DELAYED;
|
|
|
|
|
} else if (errno == EAGAIN) {
|
|
|
|
|
if (hctx->conf.debug) {
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbsd",
|
|
|
|
|
"This means that you have more incoming requests than your FastCGI backend can handle in parallel."
|
|
|
|
|
"It might help to spawn more FastCGI backends or PHP children; if not, decrease server.max-connections."
|
|
|
|
|
"The load for this FastCGI backend", proc->connection_name, "is", proc->load);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CONNECTION_OVERLOADED;
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sssb",
|
|
|
|
|
"connect failed:",
|
|
|
|
|
strerror(errno), "on",
|
|
|
|
|
proc->connection_name);
|
|
|
|
|
|
|
|
|
|
return CONNECTION_DEAD;
|
|
|
|
|
fcgi_proc_connect_error(srv, host, proc, hctx, errno);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1749,7 +1758,7 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
|
|
|
|
|
"connect succeeded: ", fcgi_fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CONNECTION_OK;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fcgi_stdin_append(server *srv, connection *con, handler_ctx *hctx, int request_id) {
|
|
|
|
@ -2106,21 +2115,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
|
|
|
|
|
if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
|
|
|
|
|
int socket_error = fdevent_connect_status(hctx->fd);
|
|
|
|
|
if (socket_error != 0) {
|
|
|
|
|
if (!hctx->proc->is_local || hctx->conf.debug) {
|
|
|
|
|
/* local procs get restarted */
|
|
|
|
|
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sssb",
|
|
|
|
|
"establishing connection failed:", strerror(socket_error),
|
|
|
|
|
"socket:", hctx->proc->connection_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fcgi_proc_disable(srv, hctx->host, hctx->proc, hctx);
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sdssdsd",
|
|
|
|
|
"backend is overloaded; we'll disable it for", hctx->host->disable_time, "seconds and send the request to another backend instead:",
|
|
|
|
|
"reconnects:", hctx->reconnects,
|
|
|
|
|
"load:", host->load);
|
|
|
|
|
|
|
|
|
|
fcgi_proc_tag_inc(srv, hctx, CONST_STR_LEN(".died"));
|
|
|
|
|
fcgi_proc_connect_error(srv, hctx->host, hctx->proc, hctx, socket_error);
|
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
|
}
|
|
|
|
|
/* go on with preparing the request */
|
|
|
|
@ -2183,53 +2178,17 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (fcgi_establish_connection(srv, hctx)) {
|
|
|
|
|
case CONNECTION_DELAYED:
|
|
|
|
|
/* connection is in progress, wait for an event and call getsockopt() below */
|
|
|
|
|
|
|
|
|
|
case 1: /* connection is in progress */
|
|
|
|
|
fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
|
|
|
|
|
|
|
|
|
|
fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
|
|
|
|
|
return HANDLER_WAIT_FOR_EVENT;
|
|
|
|
|
case CONNECTION_OVERLOADED:
|
|
|
|
|
/* cool down the backend, it is overloaded
|
|
|
|
|
* -> EAGAIN */
|
|
|
|
|
|
|
|
|
|
if (hctx->host->disable_time) {
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sdssdsd",
|
|
|
|
|
"backend is overloaded; we'll disable it for", hctx->host->disable_time, "seconds and send the request to another backend instead:",
|
|
|
|
|
"reconnects:", hctx->reconnects,
|
|
|
|
|
"load:", host->load);
|
|
|
|
|
|
|
|
|
|
hctx->proc->disabled_until = srv->cur_ts + hctx->host->disable_time;
|
|
|
|
|
fcgi_proc_set_state(hctx->host, hctx->proc, PROC_STATE_OVERLOADED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fcgi_proc_tag_inc(srv, hctx, CONST_STR_LEN(".overloaded"));
|
|
|
|
|
case -1:/* connection error */
|
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
|
case CONNECTION_DEAD:
|
|
|
|
|
/* we got a hard error from the backend like
|
|
|
|
|
* - ECONNREFUSED for tcp-ip sockets
|
|
|
|
|
* - ENOENT for unix-domain-sockets
|
|
|
|
|
*
|
|
|
|
|
* for check if the host is back in hctx->host->disable_time seconds
|
|
|
|
|
* */
|
|
|
|
|
|
|
|
|
|
fcgi_proc_disable(srv, hctx->host, hctx->proc, hctx);
|
|
|
|
|
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sdssdsd",
|
|
|
|
|
"backend died; we'll disable it for", hctx->host->disable_time, "seconds and send the request to another backend instead:",
|
|
|
|
|
"reconnects:", hctx->reconnects,
|
|
|
|
|
"load:", host->load);
|
|
|
|
|
|
|
|
|
|
fcgi_proc_tag_inc(srv, hctx, CONST_STR_LEN(".died"));
|
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
|
case CONNECTION_OK:
|
|
|
|
|
/* everything is ok, go on */
|
|
|
|
|
|
|
|
|
|
fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
|
|
|
|
|
|
|
|
|
|
case 0: /* everything is ok, go on */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
|
|
|
|
|
/* fallthrough */
|
|
|
|
|
case FCGI_STATE_PREPARE_WRITE:
|
|
|
|
|
/* ok, we have the connection */
|
|
|
|
|