Permalink
Browse files

Fixed 503 responses when Redis is down.

  • Loading branch information...
1 parent fd404c4 commit bf2f58414003a2ed1c41ef739a2d7a57f652bf01 @nicolasff committed Apr 9, 2011
Showing with 67 additions and 39 deletions.
  1. +13 −11 cmd.c
  2. +5 −1 cmd.h
  3. +2 −5 formats/bson.c
  4. +15 −0 formats/common.c
  5. +3 −0 formats/common.h
  6. +2 −1 formats/custom-type.c
  7. +2 −7 formats/json.c
  8. +2 −1 formats/raw.c
  9. +11 −10 pool.c
  10. +12 −3 worker.c
View
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
View
6 cmd.h
@@ -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);
View
@@ -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;
}
View
@@ -32,6 +32,21 @@ char *etag_new(const char *p, size_t sz) {
}
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) {
int free_cmd = 1;
View
@@ -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
View
@@ -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;
}
View
@@ -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;
}
View
@@ -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;
}
View
21 pool.c
@@ -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;
}
View
@@ -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;
}
}

0 comments on commit bf2f584

Please sign in to comment.