Skip to content

Commit

Permalink
redis: add timeout for connect and query
Browse files Browse the repository at this point in the history
This prevents OpenSIPS from blocking waiting for a connection to be
established.

Fixes #753 reported by Nick Altmann
  • Loading branch information
razvancrainea committed Jan 13, 2016
1 parent 29190f3 commit 76034ad
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 45 deletions.
47 changes: 38 additions & 9 deletions modules/cachedb_redis/README
Expand Up @@ -8,7 +8,7 @@ Edited by

Vladut-Stefan Paiu

Copyright © 2011 www.opensips-solutions.com
Copyright 2011 www.opensips-solutions.com
__________________________________________________________

Table of Contents
Expand All @@ -26,14 +26,19 @@ Vladut-Stefan Paiu
1.5. Exported Parameters

1.5.1. cachedb_url (string)
1.5.2. Exported Functions
1.5.3. Raw Query Syntax
1.5.2. connect_timeout (integer)
1.5.3. query_timeout (integer)

1.6. Exported Functions
1.7. Raw Query Syntax

List of Examples

1.1. Set cachedb_url parameter
1.2. Use Redis servers
1.3. Redis Raw Query Examples
1.3. Set connect_timeout parameter
1.4. Set connect_timeout parameter
1.5. Redis Raw Query Examples

Chapter 1. Admin Guide

Expand Down Expand Up @@ -94,9 +99,9 @@ Chapter 1. Admin Guide
Example 1.1. Set cachedb_url parameter
...
modparam("cachedb_redis", "cachedb_url","redis:group1://localhost:6379/"
);
)
modparam("cachedb_redis", "cachedb_url","redis:cluster1://random_url:888
8/");
8/")
...

Example 1.2. Use Redis servers
Expand All @@ -106,20 +111,44 @@ cache_fetch("redis:cluster1","key",$avp(10));
cache_remove("redis:cluster1","key");
...

1.5.2. Exported Functions
1.5.2. connect_timeout (integer)

This parameter specifies how many milliseconds OpenSIPS should
wait for connecting to a Redis node.
Default value is "5000 ms".

Example 1.3. Set connect_timeout parameter
...
# wait 1 seconds for Redis to connect
modparam("cachedb_redis", "connect_timeout",1000)
...

1.5.3. query_timeout (integer)

This parameter specifies how many milliseconds OpenSIPS should
wait for a query response from a Redis node.
Default value is "5000 ms".

Example 1.4. Set connect_timeout parameter
...
# wait 1 seconds for Redis queries
modparam("cachedb_redis", "query_timeout",1000)
...

1.6. Exported Functions

The module does not export functions to be used in
configuration script.

1.5.3. Raw Query Syntax
1.7. Raw Query Syntax

The cachedb_redis module allows to run RAW queries, thus taking
full advantage of the capabilities of the back-end. The query
syntax is the typical REDIS one.

Here are a couple examples of running some Redis queries :

Example 1.3. Redis Raw Query Examples
Example 1.5. Redis Raw Query Examples
...
$var(my_hash) = "my_hash_name";
$var(my_key) = "my_key_name";
Expand Down
2 changes: 2 additions & 0 deletions modules/cachedb_redis/cachedb_redis.c
Expand Up @@ -53,6 +53,8 @@ int set_connection(unsigned int type, void *val)
}

static param_export_t params[]={
{ "connect_timeout", INT_PARAM, &redis_connnection_tout},
{ "query_timeout", INT_PARAM, &redis_query_tout },
{ "cachedb_url", STR_PARAM|USE_FUNC_PARAM, (void *)&set_connection},
{0,0,0}
};
Expand Down
48 changes: 39 additions & 9 deletions modules/cachedb_redis/cachedb_redis_dbase.c
Expand Up @@ -33,16 +33,48 @@
#include <string.h>
#include <hiredis/hiredis.h>

int redis_query_tout = CACHEDB_REDIS_DEFAULT_TIMEOUT;
int redis_connnection_tout = CACHEDB_REDIS_DEFAULT_TIMEOUT;

redisContext *redis_get_ctx(char *ip, int port)
{
struct timeval tv;
static char warned = 0;
redisContext *ctx;

if (!redis_connnection_tout) {
if (!warned++)
LM_WARN("Connecting to redis without timeout might block your server\n");
ctx = redisConnect(ip,port);
} else {
tv.tv_sec = redis_connnection_tout / 1000;
tv.tv_usec = (redis_connnection_tout * 1000) % 1000000;
ctx = redisConnectWithTimeout(ip,port,tv);
}
if (ctx && ctx->err != REDIS_OK) {
LM_ERR("failed to open redis connection %s:%hu - %s\n",ip,
port,ctx->errstr);
return NULL;
}

if (redis_query_tout) {
tv.tv_sec = redis_query_tout / 1000;
tv.tv_usec = (redis_query_tout * 1000) % 1000000;
if (redisSetTimeout(ctx, tv) != REDIS_OK) {
LM_ERR("Cannot set query timeout to %dms\n", redis_query_tout);
return NULL;
}
}
return ctx;
}

int redis_connect_node(redis_con *con,cluster_node *node)
{
redisReply *rpl;

node->context = redisConnect(node->ip,node->port);
if (node->context->err != REDIS_OK) {
LM_ERR("failed to open redis connection %s:%hu - %s\n",node->ip,
node->port,node->context->errstr);
node->context = redis_get_ctx(node->ip,node->port);
if (!node->context)
return -1;
}

if (con->id->password) {
rpl = redisCommand(node->context,"AUTH %s",con->id->password);
Expand Down Expand Up @@ -93,11 +125,9 @@ int redis_connect(redis_con *con)
int len;

/* connect to redis DB */
ctx = redisConnect(con->id->host,con->id->port);
if (ctx->err != REDIS_OK) {
LM_ERR("failed to open redis connection - %s\n",ctx->errstr);
ctx = redis_get_ctx(con->id->host,con->id->port);
if (!ctx)
return -1;
}

/* auth using password, if any */
if (con->id->password) {
Expand Down
6 changes: 6 additions & 0 deletions modules/cachedb_redis/cachedb_redis_dbase.h
Expand Up @@ -39,6 +39,12 @@ typedef struct cluster_nodes {
struct cluster_nodes *next;
} cluster_node;


#define CACHEDB_REDIS_DEFAULT_TIMEOUT 5000

extern int redis_query_tout;
extern int redis_connnection_tout;

#define REDIS_SINGLE_INSTANCE (1<<0)
#define REDIS_CLUSTER_INSTANCE (1<<1)
typedef struct {
Expand Down
99 changes: 72 additions & 27 deletions modules/cachedb_redis/doc/cachedb_redis_admin.xml
@@ -1,13 +1,13 @@
<!-- Module User's Guide -->

<chapter>

<title>&adminguide;</title>

<section>
<title>Overview</title>
<para>
This module is an implementation of a cache system designed to work with a
This module is an implementation of a cache system designed to work with a
Redis server. It uses hiredis client library to connect to either a single Redis
server instance, or to a Redis Server inside a Redis Cluster.
It uses the Key-Value interface exported from the core.
Expand Down Expand Up @@ -66,8 +66,8 @@

<section>
<title>Limitations</title>


<para>
<itemizedlist>
<listitem>
Expand All @@ -90,7 +90,7 @@
None.
</para>
</section>

<section>
<title>External Libraries or Applications</title>
<para>
Expand All @@ -102,7 +102,7 @@
<para>
<emphasis>hiredis:</emphasis>
</para>

<para>
On the latest Debian based distributions, hiredis can be installed
by running 'apt-get install libhiredis-dev'
Expand All @@ -111,12 +111,12 @@
hiredis can be downloaded from: https://github.com/antirez/hiredis .
Download the archive, extract sources, run make,sudo make install.
</para>

</listitem>
</itemizedlist>
</section>
</section>

<section>
<title>Exported Parameters</title>
<section>
Expand All @@ -128,35 +128,80 @@
The prefix part of the URL will be the identifier that will be used
from the script.
</para>

<example>
<title>Set <varname>cachedb_url</varname> parameter</title>
<programlisting format="linespecific">
...
modparam("cachedb_redis", "cachedb_url","redis:group1://localhost:6379/");
modparam("cachedb_redis", "cachedb_url","redis:cluster1://random_url:8888/");
modparam("cachedb_redis", "cachedb_url","redis:group1://localhost:6379/")
modparam("cachedb_redis", "cachedb_url","redis:cluster1://random_url:8888/")
...
</programlisting>
</example>
<example>
<title>Use Redis servers </title>
<programlisting format="linespecific">
</programlisting>
</example>

<example>
<title>Use Redis servers </title>
<programlisting format="linespecific">
...
cache_store("redis:group1","key","$ru value");
cache_fetch("redis:cluster1","key",$avp(10));
cache_remove("redis:cluster1","key");
...
</programlisting>
</programlisting>
</example>
</section>

<section>
<title><varname>connect_timeout</varname> (integer)</title>
<para>
This parameter specifies how many milliseconds &osips; should wait
for connecting to a Redis node.
</para>
<emphasis>
Default value is <quote>5000 ms</quote>.
</emphasis>

<example>
<title>Set <varname>connect_timeout</varname> parameter</title>
<programlisting format="linespecific">
...
# wait 1 seconds for Redis to connect
modparam("cachedb_redis", "connect_timeout",1000)
...
</programlisting>
</example>

</section>

<section>
<title><varname>query_timeout</varname> (integer)</title>
<para>
This parameter specifies how many milliseconds &osips; should wait
for a query response from a Redis node.
</para>
<emphasis>
Default value is <quote>5000 ms</quote>.
</emphasis>

<example>
<title>Set <varname>connect_timeout</varname> parameter</title>
<programlisting format="linespecific">
...
# wait 1 seconds for Redis queries
modparam("cachedb_redis", "query_timeout",1000)
...
</programlisting>
</example>

</section>
</section>


<section>
<title>Exported Functions</title>
<para>The module does not export functions to be used
in configuration script.</para>
</section>
</section>

<section>
<title>Raw Query Syntax</title>
Expand All @@ -175,22 +220,22 @@ cache_remove("redis:cluster1","key");
$var(my_hash) = "my_hash_name";
$var(my_key) = "my_key_name";
$var(my_value) = "my_key_value";
cache_raw_query("redis","HSET $var(my_hash) $var(my_key) $var(my_value)");
cache_raw_query("redis","HSET $var(my_hash) $var(my_key) $var(my_value)");
cache_raw_query("redis","HGET $var(my_hash) $var(my_key)","$avp(result)");
xlog("We have fetched $avp(result) \n");
xlog("We have fetched $avp(result) \n");
...
$var(my_hash) = "my_hash_name";
$var(my_key1) = "my_key1_name";
$var(my_key2) = "my_key2_name";
$var(my_value1) = "my_key1_value";
$var(my_value2) = "my_key2_value";
cache_raw_query("redis","HSET $var(my_hash) $var(my_key1) $var(my_value1)");
cache_raw_query("redis","HSET $var(my_hash) $var(my_key2) $var(my_value2)");
cache_raw_query("redis","HSET $var(my_hash) $var(my_key1) $var(my_value1)");
cache_raw_query("redis","HSET $var(my_hash) $var(my_key2) $var(my_value2)");
cache_raw_query("redis","HGETALL $var(my_hash)","$avp(result)");

$var(it) = 0;
while ($(avp(result_final)[$var(it)]) != NULL) {
xlog("Multiple key reply: - we have fetched $(avp(result_final)[$var(it)]) \n");
xlog("Multiple key reply: - we have fetched $(avp(result_final)[$var(it)]) \n");
$var(it) = $var(it) + 1;
}
...
Expand All @@ -199,7 +244,7 @@ cache_remove("redis:cluster1","key");
</para>

</section>
</section>


</chapter>

0 comments on commit 76034ad

Please sign in to comment.