diff --git a/README.md b/README.md index b246cf326..4058486b2 100644 --- a/README.md +++ b/README.md @@ -456,6 +456,11 @@ The options are described in more detail below. This parameter configures the number of seconds redis communication is disabled because of errors. This works together with redis-allowed-errors parameter. The default value is 10. +* --redis-cmd-timeout + If this parameter is set to a non-zero value it will set the timeout, in milliseconds, for each command to the redis server. + If redis does not reply within the specified timeout the command will fail. The default value is 0, meaning that the commands + will have no timeout + * -b, --b2b-url Enables and sets the URI for an XMLRPC callback to be made when a call is torn down due to packet diff --git a/daemon/main.c b/daemon/main.c index e0313647d..dea8faa79 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -73,6 +73,7 @@ static int redis_num_threads; static int no_redis_required; static int redis_allowed_errors = -1; static int redis_disable_time = 10; +static int redis_cmd_timeout = 0; static char *redis_auth; static char *redis_write_auth; static char *b2b_url; @@ -282,6 +283,7 @@ static void options(int *argc, char ***argv) { { "no-redis-required", 'q', 0, G_OPTION_ARG_NONE, &no_redis_required, "Start no matter of redis connection state", NULL }, { "redis-allowed-errors", 0, 0, G_OPTION_ARG_INT, &redis_allowed_errors, "Number of allowed errors before redis is temporarily disabled", "INT" }, { "redis-disable-time", 0, 0, G_OPTION_ARG_INT, &redis_disable_time, "Number of seconds redis communication is disabled because of errors", "INT" }, + { "redis-cmd-timeout", 0, 0, G_OPTION_ARG_INT, &redis_cmd_timeout, "Sets a timeout in milliseconds for redis commands", "INT" }, { "b2b-url", 'b', 0, G_OPTION_ARG_STRING, &b2b_url, "XMLRPC URL of B2B UA" , "STRING" }, { "log-facility-cdr",0, 0, G_OPTION_ARG_STRING, &log_facility_cdr_s, "Syslog facility to use for logging CDRs", "daemon|local0|...|local7"}, { "log-facility-rtcp",0, 0, G_OPTION_ARG_STRING, &log_facility_rtcp_s, "Syslog facility to use for logging RTCP", "daemon|local0|...|local7"}, @@ -582,7 +584,7 @@ no_kernel: if (!is_addr_unspecified(&redis_write_ep.address)) { mc.redis_write = redis_new(&redis_write_ep, redis_write_db, redis_write_auth, ANY_REDIS_ROLE, no_redis_required, - redis_allowed_errors, redis_disable_time); + redis_allowed_errors, redis_disable_time, redis_cmd_timeout); if (!mc.redis_write) die("Cannot start up without running Redis %s write database! See also NO_REDIS_REQUIRED parameter.", endpoint_print_buf(&redis_write_ep)); @@ -591,10 +593,12 @@ no_kernel: if (!is_addr_unspecified(&redis_ep.address)) { mc.redis = redis_new(&redis_ep, redis_db, redis_auth, mc.redis_write ? ANY_REDIS_ROLE : MASTER_REDIS_ROLE, - no_redis_required, redis_allowed_errors, redis_disable_time); + no_redis_required, redis_allowed_errors, redis_disable_time, + redis_cmd_timeout); mc.redis_notify = redis_new(&redis_ep, redis_db, redis_auth, mc.redis_write ? ANY_REDIS_ROLE : MASTER_REDIS_ROLE, - no_redis_required, redis_allowed_errors, redis_disable_time); + no_redis_required, redis_allowed_errors, redis_disable_time, + redis_cmd_timeout); if (!mc.redis || !mc.redis_notify) die("Cannot start up without running Redis %s database! See also NO_REDIS_REQUIRED parameter.", endpoint_print_buf(&redis_ep)); diff --git a/daemon/redis.c b/daemon/redis.c index d773f682c..aa55528dc 100644 --- a/daemon/redis.c +++ b/daemon/redis.c @@ -183,6 +183,15 @@ static int redis_connect(struct redis *r, int wait) { if (r->ctx->err) goto err2; + if (r->cmd_timeout) { + struct timeval tv_cmd; + tv_cmd.tv_sec = (int) r->cmd_timeout / 1000; + tv_cmd.tv_usec = (int) (r->cmd_timeout % 1000) * 1000; + if (redisSetTimeout(r->ctx, tv_cmd)) + goto err2; + ilog(LOG_INFO, "Setting timeout for Redis commands to %d milliseconds",r->cmd_timeout); + } + if (r->auth) { if (redisCommandNR(r->ctx, "AUTH %s", r->auth)) goto err2; @@ -630,7 +639,7 @@ void redis_notify_loop(void *d) { struct redis *redis_new(const endpoint_t *ep, int db, const char *auth, enum redis_role role, int no_redis_required, int redis_allowed_errors, - int redis_disable_time) { + int redis_disable_time, int redis_cmd_timeout) { struct redis *r; r = g_slice_alloc0(sizeof(*r)); @@ -645,6 +654,7 @@ struct redis *redis_new(const endpoint_t *ep, int db, const char *auth, r->disable_time = redis_disable_time; r->restore_tick = 0; r->consecutive_errors = 0; + r->cmd_timeout = redis_cmd_timeout; mutex_init(&r->lock); if (redis_connect(r, 10)) { @@ -1686,7 +1696,7 @@ int redis_restore(struct callmaster *m, struct redis *r) { g_queue_push_tail(&ctx.r_q, redis_new(&r->endpoint, r->db, r->auth, r->role, r->no_redis_required, r->allowed_errors, - r->disable_time)); + r->disable_time,r->cmd_timeout)); gtp = g_thread_pool_new(restore_thread, &ctx, m->conf.redis_num_threads, TRUE, NULL); for (i = 0; i < calls->elements; i++) { diff --git a/daemon/redis.h b/daemon/redis.h index 2906c723c..290ced479 100644 --- a/daemon/redis.h +++ b/daemon/redis.h @@ -65,6 +65,7 @@ struct redis { int consecutive_errors; int disable_time; time_t restore_tick; + int cmd_timeout; }; struct redis_hash { @@ -96,7 +97,7 @@ INLINE gboolean g_hash_table_insert_check(GHashTable *h, gpointer k, gpointer v) void redis_notify_loop(void *d); -struct redis *redis_new(const endpoint_t *, int, const char *, enum redis_role, int, int, int); +struct redis *redis_new(const endpoint_t *, int, const char *, enum redis_role, int, int, int, int); int redis_restore(struct callmaster *, struct redis *); void redis_update(struct call *, struct redis *); void redis_update_onekey(struct call *c, struct redis *r);