Skip to content

Commit

Permalink
Issue #477: Automatically reconnect a broken Redis connection.
Browse files Browse the repository at this point in the history
Provide the `RedisOptions` directive for disabling this behavior if needed.
  • Loading branch information
Castaglia committed Aug 5, 2017
1 parent 26e5fa8 commit 71edc2b
Show file tree
Hide file tree
Showing 6 changed files with 338 additions and 144 deletions.
2 changes: 2 additions & 0 deletions RELEASE_NOTES
Expand Up @@ -22,6 +22,8 @@ ChangeLog files.

+ New Configuration Directives

RedisOptions (Issue #477)

RedisSentinel (Issue #396)


Expand Down
31 changes: 31 additions & 0 deletions doc/modules/mod_redis.html
Expand Up @@ -22,6 +22,7 @@ <h2>Directives</h2>
<li><a href="#RedisEngine">RedisEngine</a>
<li><a href="#RedisLog">RedisLog</a>
<li><a href="#RedisLogOnCommand">RedisLogOnCommand</a>
<li><a href="#RedisOptions">RedisOptions</a>
<li><a href="#RedisSentinel">RedisSentinel</a>
<li><a href="#RedisServer">RedisServer</a>
<li><a href="#RedisTimeouts">RedisTimeouts</a>
Expand Down Expand Up @@ -103,6 +104,36 @@ <h3><a name="RedisLogOnCommand">RedisLogOnCommand</a></h3>
<code>RedisLogOnCommand</code> does <b>not</b> currently support the logging
<i>classes</i> that the <code>ExtendedLog</code> directive supports.

<p>
<hr>
<h3><a name="RedisOptions">RedisOptions</a></h3>
<strong>Syntax:</strong> RedisOptions <em>opt1 ...</em><br>
<strong>Default:</strong> None<br>
<strong>Context:</strong> server config, <code>&lt;VirtualHost&gt;</code>, <code>&lt;Global&gt;</code><br>
<strong>Module:</strong> mod_redis<br>
<strong>Compatibility:</strong> 1.3.7rc1 and later

<p>
The <code>RedisOptions</code> directive is used to configure various optional
behavior of <code>mod_redis</code>.

<p>
Example:
<pre>
RedisOptions NoReconnect
</pre>

<p>
The currently implemented options are:
<ul>
<li><code>NoReconnect</code><br>
<p>
If the connection to Redis breaks unexpectedly, <code>mod_redis</code>
will attempt to <em>reconnect</em> automatically. Use this option to
disable the automatic reconnection.
</li>
</ul>

<p>
<hr>
<h3><a name="RedisSentinel">RedisSentinel</a></h3>
Expand Down
10 changes: 7 additions & 3 deletions include/redis.h
Expand Up @@ -36,8 +36,12 @@ typedef struct redis_rec pr_redis_t;
/* This function returns the pr_redis_t for the current session; if one
* does not exist, it will be allocated.
*/
pr_redis_t *pr_redis_conn_get(pool *p);
pr_redis_t *pr_redis_conn_get(pool *p, unsigned long flags);
pr_redis_t *pr_redis_conn_new(pool *p, module *owner, unsigned long flags);

/* These flags are used for tweaking connection behaviors. */
#define PR_REDIS_CONN_FL_NO_RECONNECT 0x0001

int pr_redis_conn_close(pr_redis_t *redis);
int pr_redis_conn_destroy(pr_redis_t *redis);

Expand Down Expand Up @@ -298,8 +302,8 @@ int pr_redis_sentinel_get_masters(pool *p, pr_redis_t *redis,
array_header **masters);

/* For internal use only */
int redis_set_server(const char *server, int port, const char *password,
const char *db_idx);
int redis_set_server(const char *server, int port, unsigned long flags,
const char *password, const char *db_idx);
int redis_set_sentinels(array_header *sentinels, const char *name);
int redis_set_timeouts(unsigned long connect_millis, unsigned long io_millis);

Expand Down
46 changes: 45 additions & 1 deletion modules/mod_redis.c
Expand Up @@ -47,6 +47,7 @@ module redis_module;

static int redis_engine = FALSE;
static int redis_logfd = -1;
static unsigned long redis_opts = 0UL;
static pool *redis_pool = NULL;

static void redis_exit_ev(const void *, void *);
Expand Down Expand Up @@ -1404,7 +1405,7 @@ static void log_event(cmd_rec *cmd, int flags) {
pr_redis_t *redis;
config_rec *c;

redis = pr_redis_conn_get(session.pool);
redis = pr_redis_conn_get(session.pool, redis_opts);
if (redis == NULL) {
(void) pr_log_writefile(redis_logfd, MOD_REDIS_VERSION,
"error connecting to Redis: %s", strerror(errno));
Expand Down Expand Up @@ -1589,6 +1590,36 @@ MODRET set_redislogoncommand(cmd_rec *cmd) {
return PR_HANDLED(cmd);
}

/* usage: RedisOptions opt1 opt2 ... */
MODRET set_redisoptions(cmd_rec *cmd) {
config_rec *c = NULL;
register unsigned int i = 0;
unsigned long opts = 0UL;

if (cmd->argc-1 == 0) {
CONF_ERROR(cmd, "wrong number of parameters");
}

CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);

c = add_config_param(cmd->argv[0], 1, NULL);

for (i = 1; i < cmd->argc; i++) {
if (strcmp(cmd->argv[i], "NoReconnect") == 0) {
opts |= PR_REDIS_CONN_FL_NO_RECONNECT;

} else {
CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown RedisOption '",
cmd->argv[i], "'", NULL));
}
}

c->argv[0] = pcalloc(c->pool, sizeof(unsigned long));
*((unsigned long *) c->argv[0]) = opts;

return PR_HANDLED(cmd);
}

/* usage: RedisSentinel host[:port] ... [master name] */
MODRET set_redissentinel(cmd_rec *cmd) {
register unsigned int i;
Expand Down Expand Up @@ -1946,6 +1977,18 @@ static int redis_sess_init(void) {
}
}

c = find_config(main_server->conf, CONF_PARAM, "RedisOptions", FALSE);
while (c != NULL) {
unsigned long opts = 0;

pr_signals_handle();

opts = *((unsigned long *) c->argv[0]);
redis_opts |= opts;

c = find_config_next(c, c->next, CONF_PARAM, "RedisOptions", FALSE);
}

c = find_config(main_server->conf, CONF_PARAM, "RedisSentinel", FALSE);
if (c != NULL) {
array_header *sentinels;
Expand Down Expand Up @@ -1998,6 +2041,7 @@ static conftable redis_conftab[] = {
{ "RedisEngine", set_redisengine, NULL },
{ "RedisLog", set_redislog, NULL },
{ "RedisLogOnCommand", set_redislogoncommand, NULL },
{ "RedisOptions", set_redisoptions, NULL },
{ "RedisSentinel", set_redissentinel, NULL },
{ "RedisServer", set_redisserver, NULL },
{ "RedisTimeouts", set_redistimeouts, NULL },
Expand Down

0 comments on commit 71edc2b

Please sign in to comment.