Fixed 503 responses when Redis is down.

master
Nicolas Favre-Felix 14 years ago
parent fd404c4adf
commit bf2f584140

24
cmd.c

@ -114,7 +114,7 @@ cmd_setup(struct cmd *cmd, struct http_client *client) {
}
int
cmd_response_t
cmd_run(struct worker *w, struct http_client *client,
const char *uri, size_t uri_len,
const char *body, size_t body_len) {
@ -141,7 +141,7 @@ cmd_run(struct worker *w, struct http_client *client,
param_count++;
}
if(param_count == 0) {
return -1;
return CMD_PARAM_ERROR;
}
cmd = cmd_new(param_count);
@ -168,20 +168,22 @@ cmd_run(struct worker *w, struct http_client *client,
/* check that the client is able to run this command */
if(!acl_allow_command(cmd, w->s->cfg, client)) {
return -1;
return CMD_ACL_FAIL;
}
/* check if we have to split the connection */
if(cmd_is_subscribe(cmd)) {
/* create a new connection to Redis */
ac = (redisAsyncContext*)pool_connect(w->pool, 0);
} else {
/* get a connection from the pool */
ac = (redisAsyncContext*)pool_get_context(w->pool);
}
/* no args (e.g. INFO command) */
if(!slash) {
ac = (redisAsyncContext*)pool_get_context(w->pool);
redisAsyncCommandArgv(ac, f_format, cmd, 1,
(const char **)cmd->argv, cmd->argv_len);
return 0;
return CMD_SENT;
}
p = slash + 1;
while(p < uri + uri_len) {
@ -209,12 +211,12 @@ cmd_run(struct worker *w, struct http_client *client,
}
/* send it off! */
if(!ac) {
ac = (redisAsyncContext*)pool_get_context(w->pool);
if(ac) {
cmd_send(ac, f_format, cmd);
return CMD_SENT;
}
cmd_send(ac, f_format, cmd);
return 0;
/* failed to find a suitable connection to Redis. */
return CMD_REDIS_UNAVAIL;
}
void

@ -14,6 +14,10 @@ struct worker;
struct cmd;
typedef void (*formatting_fun)(redisAsyncContext *, void *, void *);
typedef enum {CMD_SENT,
CMD_PARAM_ERROR,
CMD_ACL_FAIL,
CMD_REDIS_UNAVAIL} cmd_response_t;
struct cmd {
int fd;
@ -46,7 +50,7 @@ cmd_new(int count);
void
cmd_free(struct cmd *c);
int
cmd_response_t
cmd_run(struct worker *w, struct http_client *client,
const char *uri, size_t uri_len,
const char *body, size_t body_len);

@ -28,11 +28,8 @@ bson_reply(redisAsyncContext *c, void *r, void *privdata) {
return;
}
if (reply == NULL) {
/* FIXME */
/*
http_send_reply(client, 404, "Not Found", NULL, 0);
*/
if (reply == NULL) { /* broken Redis link */
format_send_error(cmd, 503, "Service Unavailable");
return;
}

@ -31,6 +31,21 @@ char *etag_new(const char *p, size_t sz) {
return etag;
}
void
format_send_error(struct cmd *cmd, short code, const char *msg) {
struct http_response resp;
http_response_init(&resp, code, msg);
resp.http_version = cmd->http_version;
if(cmd->keep_alive) {
http_response_set_header(&resp, "Connection", "Keep-Alive");
} else {
http_response_set_header(&resp, "Connection", "Close");
}
http_response_write(&resp, cmd->fd);
}
void
format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content_type) {

@ -10,4 +10,7 @@ format_send_reply(struct cmd *cmd,
const char *p, size_t sz,
const char *content_type);
void
format_send_error(struct cmd *cmd, short code, const char *msg);
#endif

@ -17,7 +17,8 @@ custom_type_reply(redisAsyncContext *c, void *r, void *privdata) {
int int_len;
struct http_response resp;
if(reply == NULL) {
if (reply == NULL) { /* broken Redis link */
format_send_error(cmd, 503, "Service Unavailable");
return;
}

@ -25,13 +25,8 @@ json_reply(redisAsyncContext *c, void *r, void *privdata) {
return;
}
if (reply == NULL) {
/* FIXME */
#if 0
if(client->started_responding) { /* broken, close */
http_send_reply_end(client);
}
#endif
if (reply == NULL) { /* broken Redis link */
format_send_error(cmd, 503, "Service Unavailable");
return;
}

@ -18,7 +18,8 @@ raw_reply(redisAsyncContext *c, void *r, void *privdata) {
size_t sz;
(void)c;
if (reply == NULL) {
if (reply == NULL) { /* broken Redis link */
format_send_error(cmd, 503, "Service Unavailable");
return;
}

@ -22,31 +22,31 @@ pool_new(struct worker *w, int count) {
}
static void
pool_on_connect(const redisAsyncContext *c) {
struct pool *p = c->data;
pool_on_connect(const redisAsyncContext *ac) {
struct pool *p = ac->data;
int i = 0;
printf("Connected to redis\n");
if(!p) {
if(!p || ac->err) {
return;
}
/* printf("Connected to redis\n"); */
/* add to pool */
for(i = 0; i < p->count; ++i) {
if(p->ac[i] == NULL) {
p->ac[i] = c;
p->ac[i] = ac;
return;
}
}
}
static void
pool_on_disconnect(const redisAsyncContext *c, int status) {
pool_on_disconnect(const redisAsyncContext *ac, int status) {
struct pool *p = c->data;
struct pool *p = ac->data;
int i = 0;
if (status != REDIS_OK) {
fprintf(stderr, "Error: %s\n", c->errstr);
/* fprintf(stderr, "Error: %s\n", ac->errstr); */
}
if(p == NULL) { /* no need to clean anything here. */
@ -55,13 +55,14 @@ pool_on_disconnect(const redisAsyncContext *c, int status) {
/* remove from the pool */
for(i = 0; i < p->count; ++i) {
if(p->ac[i] == c) {
if(p->ac[i] == ac) {
p->ac[i] = NULL;
break;
}
}
/* reconnect */
/* FIXME: schedule reconnect */
pool_connect(p, 1);
}
@ -89,7 +90,7 @@ pool_connect(struct pool *p, int attach) {
const char err[] = "Connection failed";
slog(s, WEBDIS_ERROR, err, sizeof(err)-1);
*/
fprintf(stderr, "Error: %s\n", ac->errstr);
/* fprintf(stderr, "Error: %s\n", ac->errstr); */
redisAsyncFree(ac);
return NULL;
}

@ -161,7 +161,7 @@ worker_process_client(struct http_client *c) {
/* printf("worker_process_client\n"); */
/* check that the command can be executed */
struct worker *w = c->w;
int ret = -1;
cmd_response_t ret = -1;
switch(c->parser.method) {
case HTTP_GET:
if(c->path_sz == 16 && memcmp(c->path, "/crossdomain.xml", 16) == 0) {
@ -192,8 +192,17 @@ worker_process_client(struct http_client *c) {
return;
}
if(ret < 0) {
http_send_error(c, 403, "Forbidden");
switch(ret) {
case CMD_ACL_FAIL:
case CMD_PARAM_ERROR:
http_send_error(c, 403, "Forbidden");
break;
case CMD_REDIS_UNAVAIL:
http_send_error(c, 503, "Service Unavailable");
break;
default:
break;
}
}

Loading…
Cancel
Save