summaryrefslogtreecommitdiff
path: root/src/mod_fastcgi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_fastcgi.c')
-rw-r--r--src/mod_fastcgi.c685
1 files changed, 311 insertions, 374 deletions
diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
index da20c76..e64351a 100644
--- a/src/mod_fastcgi.c
+++ b/src/mod_fastcgi.c
@@ -57,8 +57,10 @@
typedef struct fcgi_proc {
size_t id; /* id will be between 1 and max_procs */
- buffer *socket; /* config.socket + "-" + id */
+ buffer *unixsocket; /* config.socket + "-" + id */
unsigned port; /* config.port + pno */
+
+ buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */
pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
@@ -74,12 +76,13 @@ typedef struct fcgi_proc {
int is_local;
enum {
- PROC_STATE_UNSET, /* init-phase */
- PROC_STATE_RUNNING, /* alive */
- PROC_STATE_DIED_WAIT_FOR_PID,
- PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
- PROC_STATE_DIED, /* marked as dead, should be restarted */
- PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
+ PROC_STATE_UNSET, /* init-phase */
+ PROC_STATE_RUNNING, /* alive */
+ PROC_STATE_OVERLOADED, /* listen-queue is full,
+ don't send something to this proc for the next 2 seconds */
+ PROC_STATE_DIED_WAIT_FOR_PID, /* */
+ PROC_STATE_DIED, /* marked as dead, should be restarted */
+ PROC_STATE_KILLED /* was killed as we don't have the load anymore */
} state;
} fcgi_proc;
@@ -262,6 +265,8 @@ typedef struct {
typedef struct {
buffer *key; /* like .php */
+ int note_is_sent;
+
fcgi_extension_host **hosts;
size_t used;
@@ -358,8 +363,6 @@ typedef struct {
/* ok, we need a prototype */
static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
-int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc);
-
data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
data_integer *di;
@@ -406,8 +409,10 @@ int status_counter_set(server *srv, const char *s, size_t len, int val) {
int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
buffer_copy_string(b, "fastcgi.backend.");
buffer_append_string_buffer(b, host->id);
- buffer_append_string(b, ".");
- buffer_append_long(b, proc->id);
+ if (proc) {
+ buffer_append_string(b, ".");
+ buffer_append_long(b, proc->id);
+ }
return 0;
}
@@ -426,6 +431,15 @@ int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_
#undef CLEAN
+#define CLEAN(x) \
+ fastcgi_status_copy_procname(b, host, NULL); \
+ buffer_append_string(b, x); \
+ status_counter_set(srv, CONST_BUF_LEN(b), 0);
+
+ CLEAN(".load");
+
+#undef CLEAN
+
return 0;
}
@@ -472,7 +486,8 @@ fcgi_proc *fastcgi_process_init() {
fcgi_proc *f;
f = calloc(1, sizeof(*f));
- f->socket = buffer_init();
+ f->unixsocket = buffer_init();
+ f->connection_name = buffer_init();
f->prev = NULL;
f->next = NULL;
@@ -485,7 +500,8 @@ void fastcgi_process_free(fcgi_proc *f) {
fastcgi_process_free(f->next);
- buffer_free(f->socket);
+ buffer_free(f->unixsocket);
+ buffer_free(f->connection_name);
free(f);
}
@@ -669,8 +685,8 @@ FREE_FUNC(mod_fastcgi_free) {
if (proc->pid != 0) kill(proc->pid, SIGTERM);
if (proc->is_local &&
- !buffer_is_empty(proc->socket)) {
- unlink(proc->socket->ptr);
+ !buffer_is_empty(proc->unixsocket)) {
+ unlink(proc->unixsocket->ptr);
}
}
@@ -678,8 +694,8 @@ FREE_FUNC(mod_fastcgi_free) {
if (proc->pid != 0) kill(proc->pid, SIGTERM);
if (proc->is_local &&
- !buffer_is_empty(proc->socket)) {
- unlink(proc->socket->ptr);
+ !buffer_is_empty(proc->unixsocket)) {
+ unlink(proc->unixsocket->ptr);
}
}
}
@@ -799,24 +815,28 @@ static int fcgi_spawn_connection(server *srv,
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sdb",
- "new proc, socket:", proc->port, proc->socket);
+ "new proc, socket:", proc->port, proc->unixsocket);
}
- if (!buffer_is_empty(proc->socket)) {
+ if (!buffer_is_empty(proc->unixsocket)) {
memset(&fcgi_addr, 0, sizeof(fcgi_addr));
#ifdef HAVE_SYS_UN_H
fcgi_addr_un.sun_family = AF_UNIX;
- strcpy(fcgi_addr_un.sun_path, proc->socket->ptr);
+ strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
#ifdef SUN_LEN
servlen = SUN_LEN(&fcgi_addr_un);
#else
/* stevens says: */
- servlen = proc->socket->used - 1 + sizeof(fcgi_addr_un.sun_family);
+ servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
#endif
socket_type = AF_UNIX;
fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
+
+ buffer_copy_string(proc->connection_name, "unix:");
+ buffer_append_string_buffer(proc->connection_name, proc->unixsocket);
+
#else
log_error_write(srv, __FILE__, __LINE__, "s",
"ERROR: Unix Domain sockets are not supported.");
@@ -859,6 +879,11 @@ static int fcgi_spawn_connection(server *srv,
socket_type = AF_INET;
fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
+
+ buffer_copy_string(proc->connection_name, "tcp:");
+ buffer_append_string_buffer(proc->connection_name, host->host);
+ buffer_append_string(proc->connection_name, ":");
+ buffer_append_long(proc->connection_name, proc->port);
}
if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
@@ -872,8 +897,9 @@ static int fcgi_spawn_connection(server *srv,
pid_t child;
int val;
- if (!buffer_is_empty(proc->socket)) {
- unlink(proc->socket->ptr);
+ if (errno != ENOENT &&
+ !buffer_is_empty(proc->unixsocket)) {
+ unlink(proc->unixsocket->ptr);
}
close(fcgi_fd);
@@ -894,10 +920,9 @@ static int fcgi_spawn_connection(server *srv,
/* create socket */
if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
- log_error_write(srv, __FILE__, __LINE__, "sbds",
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
"bind failed for:",
- proc->socket,
- proc->port,
+ proc->connection_name,
strerror(errno));
return -1;
}
@@ -1040,7 +1065,7 @@ static int fcgi_spawn_connection(server *srv,
WTERMSIG(status));
if (WTERMSIG(status) == 11) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"to be exact: it seg-fault, crashed, died, ... you get the idea." );
log_error_write(srv, __FILE__, __LINE__, "s",
"If this is PHP try to remove the byte-code caches for now and try again.");
@@ -1068,7 +1093,7 @@ static int fcgi_spawn_connection(server *srv,
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sb",
"(debug) socket is already used, won't spawn:",
- proc->socket);
+ proc->connection_name);
}
}
@@ -1240,9 +1265,12 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
if ((!buffer_is_empty(host->host) || host->port) &&
!buffer_is_empty(host->unixsocket)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "either host+port or socket");
-
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "either host/port or socket have to be set in:",
+ da->key, "= (",
+ da_ext->key, " => (",
+ da_host->key, " ( ...");
+
return HANDLER_ERROR;
}
@@ -1250,8 +1278,12 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
/* unix domain socket */
if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "path of the unixdomain socket is too large");
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "unixsocket is too long in:",
+ da->key, "= (",
+ da_ext->key, " => (",
+ da_host->key, " ( ...");
+
return HANDLER_ERROR;
}
} else {
@@ -1259,21 +1291,20 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
if (buffer_is_empty(host->host) &&
buffer_is_empty(host->bin_path)) {
- log_error_write(srv, __FILE__, __LINE__, "sbbbs",
- "missing key (string):",
- da->key,
- da_ext->key,
- da_host->key,
- "host");
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "host or binpath have to be set in:",
+ da->key, "= (",
+ da_ext->key, " => (",
+ da_host->key, " ( ...");
return HANDLER_ERROR;
} else if (host->port == 0) {
- log_error_write(srv, __FILE__, __LINE__, "sbbbs",
- "missing key (short):",
- da->key,
- da_ext->key,
- da_host->key,
- "port");
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "port has to be set in:",
+ da->key, "= (",
+ da_ext->key, " => (",
+ da_host->key, " ( ...");
+
return HANDLER_ERROR;
}
}
@@ -1308,9 +1339,9 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
if (buffer_is_empty(host->unixsocket)) {
proc->port = host->port + pno;
} else {
- buffer_copy_string_buffer(proc->socket, host->unixsocket);
- buffer_append_string(proc->socket, "-");
- buffer_append_long(proc->socket, pno);
+ buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
+ buffer_append_string(proc->unixsocket, "-");
+ buffer_append_long(proc->unixsocket, pno);
}
if (s->debug) {
@@ -1346,7 +1377,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
if (buffer_is_empty(host->unixsocket)) {
proc->port = host->port;
} else {
- buffer_copy_string_buffer(proc->socket, host->unixsocket);
+ buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
}
fastcgi_status_init(srv, p->statuskey, host, proc);
@@ -1477,14 +1508,13 @@ void fcgi_connection_close(server *srv, handler_ctx *hctx) {
status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sddb",
- "release proc:",
- hctx->fd,
- hctx->proc->pid, hctx->proc->socket);
+ log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
+ "released proc:",
+ "pid:", hctx->proc->pid,
+ "socket:", hctx->proc->connection_name,
+ "load:", hctx->proc->load);
}
}
-
- fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
}
@@ -1519,6 +1549,7 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
fdevent_unregister(srv->ev, hctx->fd);
close(hctx->fd);
srv->cur_fds--;
+ hctx->fd = -1;
}
fcgi_requestid_del(srv, p, hctx->request_id);
@@ -1528,16 +1559,20 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
hctx->request_id = 0;
hctx->reconnects++;
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sddb",
- "release proc:",
- hctx->fd,
- hctx->proc->pid, hctx->proc->socket);
+ if (p->conf.debug > 2) {
+ if (hctx->proc) {
+ log_error_write(srv, __FILE__, __LINE__, "sdb",
+ "release proc for reconnect:",
+ hctx->proc->pid, hctx->proc->connection_name);
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "release proc for reconnect:",
+ hctx->host->unixsocket);
+ }
}
- if (hctx->proc) {
+ if (hctx->proc && hctx->got_proc) {
hctx->proc->load--;
- fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
}
/* perhaps another host gives us more luck */
@@ -1637,18 +1672,24 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
memset(&fcgi_addr, 0, sizeof(fcgi_addr));
- if (!buffer_is_empty(proc->socket)) {
+ if (!buffer_is_empty(proc->unixsocket)) {
#ifdef HAVE_SYS_UN_H
/* use the unix domain socket */
fcgi_addr_un.sun_family = AF_UNIX;
- strcpy(fcgi_addr_un.sun_path, proc->socket->ptr);
+ strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
#ifdef SUN_LEN
servlen = SUN_LEN(&fcgi_addr_un);
#else
/* stevens says: */
- servlen = proc->socket->used - 1 + sizeof(fcgi_addr_un.sun_family);
+ servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
#endif
fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
+
+ if (buffer_is_empty(proc->connection_name)) {
+ /* on remote spawing we have to set the connection-name now */
+ buffer_copy_string(proc->connection_name, "unix:");
+ buffer_append_string_buffer(proc->connection_name, proc->unixsocket);
+ }
#else
return -1;
#endif
@@ -1665,32 +1706,40 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
servlen = sizeof(fcgi_addr_in);
fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
+
+ if (buffer_is_empty(proc->connection_name)) {
+ /* on remote spawing we have to set the connection-name now */
+ buffer_copy_string(proc->connection_name, "tcp:");
+ buffer_append_string_buffer(proc->connection_name, host->host);
+ buffer_append_string(proc->connection_name, ":");
+ buffer_append_long(proc->connection_name, proc->port);
+ }
}
if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
if (errno == EINPROGRESS ||
errno == EALREADY ||
errno == EINTR) {
- if (hctx->conf.debug) {
+ if (hctx->conf.debug > 2) {
log_error_write(srv, __FILE__, __LINE__, "sb",
- "connect delayed, will continue later:", host->host);
+ "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__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sbsd",
"This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
"Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
- "The load for this fastcgi backend is:", proc->load);
+ "The load for this fastcgi backend", proc->connection_name, "is", proc->load);
}
return CONNECTION_OVERLOADED;
} else {
- log_error_write(srv, __FILE__, __LINE__, "ssdb",
+ log_error_write(srv, __FILE__, __LINE__, "sssb",
"connect failed:",
- strerror(errno),
- proc->port, proc->socket);
+ strerror(errno), "on",
+ proc->connection_name);
return CONNECTION_DEAD;
}
@@ -2378,12 +2427,10 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
b->used = r + 1; /* one extra for the fake \0 */
b->ptr[b->used - 1] = '\0';
} else {
- log_error_write(srv, __FILE__, __LINE__, "ssdsbsbsd",
+ log_error_write(srv, __FILE__, __LINE__, "ssdsb",
"unexpected end-of-file (perhaps the fastcgi process died):",
"pid:", proc->pid,
- "socket:", proc->socket,
- "host:", host->host,
- "port:", proc->port);
+ "socket:", proc->connection_name);
return -1;
}
@@ -2514,222 +2561,97 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
return fin;
}
-int fcgi_proclist_sort_up(server *srv, fcgi_extension_host *host, fcgi_proc *proc) {
- fcgi_proc *p;
-
- UNUSED(srv);
-
- /* we have been the smallest of the current list
- * and we want to insert the node sorted as soon
- * possible
- *
- * 1 0 0 0 1 1 1
- * | ^
- * | |
- * +------+
- *
- */
-
- /* nothing to sort, only one element */
- if (host->first == proc && proc->next == NULL) return 0;
-
- for (p = proc; p->next && p->next->load < proc->load; p = p->next);
-
- /* no need to move something
- *
- * 1 2 2 2 3 3 3
- * ^
- * |
- * +
- *
- */
- if (p == proc) return 0;
-
- if (host->first == proc) {
- /* we have been the first elememt */
-
- host->first = proc->next;
- host->first->prev = NULL;
- }
-
- /* disconnect proc */
-
- if (proc->prev) proc->prev->next = proc->next;
- if (proc->next) proc->next->prev = proc->prev;
-
- /* proc should be right of p */
-
- proc->next = p->next;
- proc->prev = p;
- if (p->next) p->next->prev = proc;
- p->next = proc;
-#if 0
- for(p = host->first; p; p = p->next) {
- log_error_write(srv, __FILE__, __LINE__, "dd",
- p->pid, p->load);
- }
-#else
- UNUSED(srv);
-#endif
-
- return 0;
-}
-
-int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc) {
- fcgi_proc *p;
-
- UNUSED(srv);
-
- /* we have been the smallest of the current list
- * and we want to insert the node sorted as soon
- * possible
- *
- * 0 0 0 0 1 0 1
- * ^ |
- * | |
- * +----------+
- *
- *
- * the basic is idea is:
- * - the last active fastcgi process should be still
- * in ram and is not swapped out yet
- * - processes that are not reused will be killed
- * after some time by the trigger-handler
- * - remember it as:
- * everything > 0 is hot
- * all unused procs are colder the more right they are
- * ice-cold processes are propably unused since more
- * than 'unused-timeout', are swaped out and won't be
- * reused in the next seconds anyway.
- *
- */
-
- /* nothing to sort, only one element */
- if (host->first == proc && proc->next == NULL) return 0;
-
- for (p = host->first; p != proc && p->load < proc->load; p = p->next);
-
-
- /* no need to move something
- *
- * 1 2 2 2 3 3 3
- * ^
- * |
- * +
- *
- */
- if (p == proc) return 0;
-
- /* we have to move left. If we are already the first element
- * we are done */
- if (host->first == proc) return 0;
-
- /* release proc */
- if (proc->prev) proc->prev->next = proc->next;
- if (proc->next) proc->next->prev = proc->prev;
-
- /* proc should be left of p */
- proc->next = p;
- proc->prev = p->prev;
- if (p->prev) p->prev->next = proc;
- p->prev = proc;
-
- if (proc->prev == NULL) host->first = proc;
-#if 0
- for(p = host->first; p; p = p->next) {
- log_error_write(srv, __FILE__, __LINE__, "dd",
- p->pid, p->load);
- }
-#else
- UNUSED(srv);
-#endif
-
- return 0;
-}
-
static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
fcgi_proc *proc;
for (proc = host->first; proc; proc = proc->next) {
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
+ int status;
+
+ if (p->conf.debug > 2) {
+ log_error_write(srv, __FILE__, __LINE__, "sbdddd",
"proc:",
- host->host, proc->port,
- proc->socket,
+ proc->connection_name,
proc->state,
proc->is_local,
proc->load,
proc->pid);
}
- if (!proc->is_local) {
- /*
- * external servers might get disabled
- *
- * enable the server again, perhaps it is back again
- */
-
- if ((proc->state == PROC_STATE_DISABLED) &&
- (srv->cur_ts > proc->disabled_until)) {
- proc->state = PROC_STATE_RUNNING;
- host->active_procs++;
-
- fastcgi_status_copy_procname(p->statuskey, host, proc);
- buffer_append_string(p->statuskey, ".disabled");
+ /*
+ * if the remote side is overloaded, we check back after <n> seconds
+ *
+ */
+ switch (proc->state) {
+ case PROC_STATE_KILLED:
+ case PROC_STATE_UNSET:
+ /* this should never happen as long as adaptive spawing is disabled */
+ assert(0);
- status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 0);
+ break;
+ case PROC_STATE_RUNNING:
+ break;
+ case PROC_STATE_OVERLOADED:
+ if (srv->cur_ts <= proc->disabled_until) break;
+
+ proc->state = PROC_STATE_RUNNING;
+ host->active_procs++;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbdb",
+ "fcgi-server re-enabled:",
+ host->host, host->port,
+ host->unixsocket);
+ break;
+ case PROC_STATE_DIED_WAIT_FOR_PID:
+ /* non-local procs don't have PIDs to wait for */
+ if (!proc->is_local) break;
- log_error_write(srv, __FILE__, __LINE__, "sbdb",
- "fcgi-server re-enabled:",
- host->host, host->port,
- host->unixsocket);
- }
- } else {
/* the child should not terminate at all */
- int status;
- if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
- switch(waitpid(proc->pid, &status, WNOHANG)) {
- case 0:
- /* child is still alive */
- break;
- case -1:
- break;
- default:
- if (WIFEXITED(status)) {
+ switch(waitpid(proc->pid, &status, WNOHANG)) {
+ case 0:
+ /* child is still alive */
+ break;
+ case -1:
+ break;
+ default:
+ if (WIFEXITED(status)) {
#if 0
- log_error_write(srv, __FILE__, __LINE__, "sdsd",
- "child exited, pid:", proc->pid,
- "status:", WEXITSTATUS(status));
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
+ "child exited, pid:", proc->pid,
+ "status:", WEXITSTATUS(status));
#endif
- } else if (WIFSIGNALED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child signaled:",
- WTERMSIG(status));
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child died somehow:",
- status);
- }
-
- proc->state = PROC_STATE_DIED;
- break;
+ } else if (WIFSIGNALED(status)) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child signaled:",
+ WTERMSIG(status));
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child died somehow:",
+ status);
}
+
+ proc->state = PROC_STATE_DIED;
+ break;
}
+
+ /* fall through if we have a dead proc now */
+ if (proc->state != PROC_STATE_DIED) break;
+
+ case PROC_STATE_DIED:
+ /* local proc get restarted by us,
+ * remote ones hopefully by the admin */
+
+ if (proc->is_local) {
+ /* we still have connections bound to this proc,
+ * let them terminate first */
+ if (proc->load != 0) break;
- /*
- * local servers might died, but we restart them
- *
- */
- if (proc->state == PROC_STATE_DIED &&
- proc->load == 0) {
/* restart the child */
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
+ log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
"--- fastcgi spawning",
- "\n\tport:", host->port,
- "\n\tsocket", host->unixsocket,
+ "\n\tsocket", proc->connection_name,
"\n\tcurrent:", 1, "/", host->min_procs);
}
@@ -2738,9 +2660,17 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h
"ERROR: spawning fcgi failed.");
return HANDLER_ERROR;
}
-
- fcgi_proclist_sort_down(srv, host, proc);
+ } else {
+ if (srv->cur_ts <= proc->disabled_until) break;
+
+ proc->state = PROC_STATE_RUNNING;
+ host->active_procs++;
+
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "fcgi-server re-enabled:",
+ proc->connection_name);
}
+ break;
}
}
@@ -2751,6 +2681,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
plugin_data *p = hctx->plugin_data;
fcgi_extension_host *host= hctx->host;
connection *con = hctx->remote_conn;
+ fcgi_proc *proc;
int ret;
@@ -2763,6 +2694,10 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
host->host->used,
host->port,
host->unixsocket->used);
+
+ hctx->proc->disabled_until = srv->cur_ts + 10;
+ hctx->proc->state = PROC_STATE_DIED;
+
return HANDLER_ERROR;
}
@@ -2776,18 +2711,29 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"getsockopt failed:", strerror(errno));
+ hctx->proc->disabled_until = srv->cur_ts + 10;
+ hctx->proc->state = PROC_STATE_DIED;
+
return HANDLER_ERROR;
}
if (socket_error != 0) {
if (!hctx->proc->is_local || p->conf.debug) {
/* local procs get restarted */
- log_error_write(srv, __FILE__, __LINE__, "sssd",
+ log_error_write(srv, __FILE__, __LINE__, "sssb",
"establishing connection failed:", strerror(socket_error),
- "port:", hctx->proc->port);
+ "socket:", hctx->proc->connection_name);
}
- hctx->proc->disabled_until = srv->cur_ts + 10;
+ hctx->proc->disabled_until = srv->cur_ts + 5;
+
+ if (hctx->proc->is_local) {
+ hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
+ } else {
+ hctx->proc->state = PROC_STATE_DIED;
+ }
+
+ hctx->proc->state = PROC_STATE_DIED;
fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
buffer_append_string(p->statuskey, ".died");
@@ -2807,18 +2753,27 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
break;
case FCGI_STATE_INIT:
/* do we have a running process for this host (max-procs) ? */
+ hctx->proc = NULL;
- for (hctx->proc = hctx->host->first;
- hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
- hctx->proc = hctx->proc->next);
+ for (proc = hctx->host->first;
+ proc && proc->state != PROC_STATE_RUNNING;
+ proc = proc->next);
/* all childs are dead */
- if (hctx->proc == NULL) {
+ if (proc == NULL) {
hctx->fde_ndx = -1;
return HANDLER_ERROR;
}
+ hctx->proc = proc;
+
+ /* check the other procs if they have a lower load */
+ for (proc = proc->next; proc; proc = proc->next) {
+ if (proc->state != PROC_STATE_RUNNING) continue;
+ if (proc->load < hctx->proc->load) hctx->proc = proc;
+ }
+
ret = host->unixsocket->used ? AF_UNIX : AF_INET;
if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
@@ -2863,14 +2818,14 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
/* cool down the backend, it is overloaded
* -> EAGAIN */
- log_error_write(srv, __FILE__, __LINE__, "ssdsdb",
+ log_error_write(srv, __FILE__, __LINE__, "ssdsd",
"backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:",
"reconnects:", hctx->reconnects,
- "load:", host->load,
- host->unixsocket);
+ "load:", host->load);
hctx->proc->disabled_until = srv->cur_ts + 2;
+ hctx->proc->state = PROC_STATE_OVERLOADED;
fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
buffer_append_string(p->statuskey, ".overloaded");
@@ -2883,11 +2838,21 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
* - ECONNREFUSED for tcp-ip sockets
* - ENOENT for unix-domain-sockets
*
- * for check if the host is back in 10 seconds
+ * for check if the host is back in 5 seconds
* */
- hctx->proc->disabled_until = srv->cur_ts + 10;
-
+ hctx->proc->disabled_until = srv->cur_ts + 5;
+ if (hctx->proc->is_local) {
+ hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
+ } else {
+ hctx->proc->state = PROC_STATE_DIED;
+ }
+
+ log_error_write(srv, __FILE__, __LINE__, "ssdsd",
+ "backend died, we disable it for a 5 seconds and send the request to another backend instead:",
+ "reconnects:", hctx->reconnects,
+ "load:", host->load);
+
fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
buffer_append_string(p->statuskey, ".died");
@@ -2919,24 +2884,27 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
+ /* the proc-load */
fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
buffer_append_string(p->statuskey, ".load");
status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
+ /* the host-load */
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL);
+ buffer_append_string(p->statuskey, ".load");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load);
+
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sddbdd",
+ log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
"got proc:",
- hctx->fd,
- hctx->proc->pid,
- hctx->proc->socket,
- hctx->proc->port,
- hctx->proc->load);
+ "pid:", hctx->proc->pid,
+ "socket:", hctx->proc->connection_name,
+ "load:", hctx->proc->load);
}
/* move the proc-list entry down the list */
- fcgi_proclist_sort_up(srv, hctx->host, hctx->proc);
-
if (hctx->request_id == 0) {
hctx->request_id = fcgi_requestid_new(srv, p);
} else {
@@ -3098,43 +3066,7 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
if (hctx->state == FCGI_STATE_INIT ||
hctx->state == FCGI_STATE_CONNECT_DELAYED) {
- /* connect() or getsockopt() failed,
- * restart the request-handling
- */
- if (proc) {
- if (proc->is_local) {
-
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sbdb",
- "connect() to fastcgi failed, restarting the request-handling:",
- host->host,
- proc->port,
- proc->socket);
- }
-
- /*
- * several hctx might reference the same proc
- *
- * Only one of them should mark the proc as dead all the other
- * ones should just take a new one.
- *
- * If a new proc was started with the old struct this might lead
- * the mark a perfect proc as dead otherwise
- *
- */
- if (proc->state == PROC_STATE_RUNNING &&
- hctx->pid == proc->pid) {
- proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
- }
- } else {
- proc->state = PROC_STATE_DISABLED;
- }
- host->active_procs--;
- fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
- buffer_append_string(p->statuskey, ".disabled");
-
- status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 1);
- }
+ if (proc) host->active_procs--;
fcgi_restart_dead_procs(srv, p, host);
@@ -3247,18 +3179,18 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
}
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
+ log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
"--- fastcgi spawning",
- "\n\tport:", host->port,
- "\n\tsocket", host->unixsocket,
+ "\n\tsocket", proc->connection_name,
"\n\tcurrent:", 1, "/", host->min_procs);
}
if (fcgi_spawn_connection(srv, p, host, proc)) {
- /* child died */
+ /* respawning failed, retry later */
proc->state = PROC_STATE_DIED;
- } else {
- fcgi_proclist_sort_down(srv, host, proc);
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "respawning failed, will retry later");
}
break;
@@ -3272,18 +3204,18 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
hctx->reconnects < 5) {
fcgi_reconnect(srv, hctx);
- log_error_write(srv, __FILE__, __LINE__, "ssdsd",
- "response not received, request not sent, reconnecting.",
- "connection-fd:", con->fd,
- "fcgi-fd:", hctx->fd);
+ log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
+ "response not received, request not sent",
+ "on socket:", proc->connection_name,
+ "for", con->uri.path, ", reconnecting");
return HANDLER_WAIT_FOR_FD;
}
-
- log_error_write(srv, __FILE__, __LINE__, "sosdsd",
+
+ log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
"response not received, request sent:", hctx->wb->bytes_out,
- "connection-fd:", con->fd,
- "fcgi-fd:", hctx->fd);
+ "on socket:", proc->connection_name,
+ "for", con->uri.path, ", closing connection");
fcgi_connection_close(srv, hctx);
@@ -3295,10 +3227,10 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
/* response might have been already started, kill the connection */
fcgi_connection_close(srv, hctx);
- log_error_write(srv, __FILE__, __LINE__, "ssdsd",
- "response already sent out, termination connection",
- "connection-fd:", con->fd,
- "fcgi-fd:", hctx->fd);
+ log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
+ "response already sent out, but backend returned error",
+ "on socket:", proc->connection_name,
+ "for", con->uri.path, ", terminating connection");
connection_set_state(srv, con, CON_STATE_ERROR);
}
@@ -3351,7 +3283,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
"error: unexpected close of fastcgi connection for",
con->uri.path,
- "(no fastcgi process on host: ",
+ "(no fastcgi process on host:",
host->host,
", port: ",
host->port,
@@ -3425,9 +3357,7 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
fn = uri_path_handler ? con->uri.path : con->physical.path;
- if (fn->used == 0) {
- return HANDLER_ERROR;
- }
+ if (buffer_is_empty(fn)) return HANDLER_GO_ON;
s_len = fn->used - 1;
@@ -3519,14 +3449,23 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
/* sorry, we don't have a server alive for this ext */
buffer_reset(con->physical.path);
con->http_status = 500;
-
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "no fcgi-handler found for:",
- fn);
+
+ /* only send the 'no handler' once */
+ if (!extension->note_is_sent) {
+ extension->note_is_sent = 1;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbsbs",
+ "all handlers for ", con->uri.path,
+ "on", extension->key,
+ "are down.");
+ }
return HANDLER_FINISHED;
}
+ /* a note about no handler is not sent yey */
+ extension->note_is_sent = 0;
+
/*
* if check-local is disabled, use the uri.path handler
*
@@ -3708,48 +3647,46 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
host->num_procs < host->max_procs &&
(sum_load / host->num_procs) > host->max_load_per_proc) {
/* overload, spawn new child */
- fcgi_proc *fp = NULL;
-
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "s",
"overload detected, spawning a new child");
}
- for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
+ for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next);
- if (fp) {
- if (fp == host->unused_procs) host->unused_procs = fp->next;
+ if (proc) {
+ if (proc == host->unused_procs) host->unused_procs = proc->next;
- if (fp->next) fp->next->prev = NULL;
+ if (proc->next) proc->next->prev = NULL;
host->max_id++;
} else {
- fp = fastcgi_process_init();
- fp->id = host->max_id++;
+ proc = fastcgi_process_init();
+ proc->id = host->max_id++;
}
host->num_procs++;
if (buffer_is_empty(host->unixsocket)) {
- fp->port = host->port + fp->id;
+ proc->port = host->port + proc->id;
} else {
- buffer_copy_string_buffer(fp->socket, host->unixsocket);
- buffer_append_string(fp->socket, "-");
- buffer_append_long(fp->socket, fp->id);
+ buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
+ buffer_append_string(proc->unixsocket, "-");
+ buffer_append_long(proc->unixsocket, proc->id);
}
- if (fcgi_spawn_connection(srv, p, host, fp)) {
+ if (fcgi_spawn_connection(srv, p, host, proc)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"ERROR: spawning fcgi failed.");
return HANDLER_ERROR;
}
- fp->prev = NULL;
- fp->next = host->first;
+ proc->prev = NULL;
+ proc->next = host->first;
if (host->first) {
- host->first->prev = fp;
+ host->first->prev = proc;
}
- host->first = fp;
+ host->first = proc;
}
for (proc = host->first; proc; proc = proc->next) {
@@ -3764,7 +3701,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "ssbsd",
"idle-timeout reached, terminating child:",
- "socket:", proc->socket,
+ "socket:", proc->connection_name,
"pid", proc->pid);
}
@@ -3786,7 +3723,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
log_error_write(srv, __FILE__, __LINE__, "ssbsd",
"killed:",
- "socket:", proc->socket,
+ "socket:", proc->connection_name,
"pid", proc->pid);
host->num_procs--;
@@ -3827,7 +3764,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
if (proc->state != PROC_STATE_KILLED) {
log_error_write(srv, __FILE__, __LINE__, "sdb",
"child exited:",
- WEXITSTATUS(status), proc->socket);
+ WEXITSTATUS(status), proc->connection_name);
}
} else if (WIFSIGNALED(status)) {
if (WTERMSIG(status) != SIGTERM) {