<!-- Module User's Guide -->

<chapter>

	<title>&adminguide;</title>

	<section id="overview" xreflabel="Overview">
	<title>Overview</title>
	<para>
		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.
	</para>
	<para>
	</para>
	</section>


	<section>
	<title>Advantages</title>
	<para>
		<itemizedlist>
			<listitem>
			<para>
				<emphasis>memory costs are no longer on the server
				</emphasis>
			</para>
			</listitem>

			<listitem>
			<para>
				<emphasis>many servers can be used inside a cluster, so the memory
				is virtually unlimited</emphasis>
			</para>
			</listitem>

			<listitem>
			<para>
				<emphasis>the cache is 100% persistent. A restart
					of OpenSIPS server will not affect the DB. The Redis DB is also
				persistent so it can also be restarted without loss of information.</emphasis>
			</para>
			</listitem>

			<listitem>
			<para>
				<emphasis>redis is an open-source project so
				it can be used to exchange data
				 with various other applications</emphasis>
			</para>
			</listitem>

			<listitem>
			<para>
				<emphasis>By creating a Redis Cluster, multiple OpenSIPS
				instances can easily share key-value information</emphasis>
			</para>
			</listitem>

		</itemizedlist>
	</para>
	<para>
	</para>
	</section>

	<section>
	<title>Limitations</title>


		<para>
			<itemizedlist>
			<listitem>
			<para>
			<emphasis>
		keys (in key:value pairs) may not contain spaces or control characters
		</emphasis>
			</para>
			</listitem>

		</itemizedlist>
		</para>
	</section>

	<section id="dependencies" xreflabel="Dependencies">
	<title>Dependencies</title>
	<section>
		<title>&osips; Modules</title>
		<para>
		The following modules must be loaded before this module:
			<itemizedlist>
			<listitem>
			<para>
				<emphasis>If a <xref linkend="param_use_tls"/> is defined, the <emphasis role='bold'>tls_mgm</emphasis> module will need to be loaded as well</emphasis>.
			</para>
			</listitem>
			</itemizedlist>
		</para>
	</section>

	<section>
		<title>External Libraries or Applications</title>
		<para>
		The following libraries or applications must be installed before running
		&osips; with this module loaded:
		</para>
			<itemizedlist>
			<listitem>
			<para>
				<emphasis>hiredis:</emphasis>
			</para>

			<para>
				On the latest Debian based distributions, hiredis can be installed
				by running 'apt-get install libhiredis-dev'

				Alternatively, if hiredis is not available on your OS repos,
				hiredis can be downloaded from: https://github.com/antirez/hiredis .
				Download the archive, extract sources, run make,sudo make install.
			</para>
			<para>
				If TLS connections are enabled via the <xref linkend="param_use_tls"/> modparam,
				<emphasis>hiredis</emphasis> needs to be compiled with TLS support.
			</para>

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

	<section id="exported_parameters" xreflabel="Exported Parameters">
		<title>Exported Parameters</title>
		<section id="param_cachedb_url" xreflabel="cachedb_url">
		<title><varname>cachedb_url</varname> (string)</title>
		<para>
			The URLs of the server groups that OpenSIPS will connect to in order
			to use, from script, the cache_store(), cache_fetch(), etc. operations.
			It may be set more than once.  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">
...
# single-instance URLs (Redis Server or Redis Cluster)
modparam("cachedb_redis", "cachedb_url", "redis:group1://localhost:6379/")
modparam("cachedb_redis", "cachedb_url", "redis:cluster1://random_url:8888/")

# multi-instance URL (will perform circular <emphasis role='bold'>failover</emphasis> on each query)
modparam("cachedb_redis", "cachedb_url",
	"redis:ha://localhost,host_a:6380,host_b:6381,host_c/")
...
		</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>
			</example>
		</section>

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

		<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 id="param_query_timeout" xreflabel="query_timeout">
		<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>
		<para>
		<emphasis>
			Default value is <quote>5000 ms</quote>.
		</emphasis>
		</para>

		<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 id="param_shutdown_on_error" xreflabel="shutdown_on_error">
		<title><varname>shutdown_on_error</varname> (integer)</title>
		<para>
			By setting this parameter to 1, &osips; will abort startup if
		the initial connection to Redis is not possible. Runtime reconnect
		behavior is unaffected by this parameter, and is always enabled.
		</para>
		<para>
		<emphasis>
			Default value is <quote>0</quote> (disabled).
		</emphasis>
		</para>

		<example>
		<title>Set the <varname>shutdown_on_error</varname> parameter</title>
		<programlisting format="linespecific">
...
# abort OpenSIPS startup if Redis is down
modparam("cachedb_redis", "shutdown_on_error", 1)
...
		</programlisting>
		</example>

		</section>

		 <section id="param_use_tls" xreflabel="use_tls">
		<title><varname>use_tls</varname> (integer)</title>
		<para>
		Setting this parameter will allow you to use TLS for Redis connections.
		In order to enable TLS for a specific connection, you can use the
		"tls_domain=<emphasis>dom_name</emphasis>" URL parameter in the cachedb_url
		of this module (or other modules that use the CacheDB interface). This should
		be placed at the end of the URL after the '?' character.
		</para>
		<para>
		When using this parameter, you must also ensure that
		<emphasis>tls_mgm</emphasis> is loaded and properly configured. Refer to
		the the module for additional info regarding TLS client domains.
		</para>
		<para>
		Note that TLS is supported by Redis starting with version 6.0. Also, it is
		an optional feature enabled at compile time and might not be included in the
		standard Redis packages available for your OS.
		</para>
		<para>
		<emphasis>
			Default value is <emphasis role='bold'>0</emphasis> (not enabled)
		</emphasis>
		</para>
		<example>
		<title>Set the <varname>use_tls</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("tls_mgm", "client_domain", "redis")
modparam("tls_mgm", "certificate", "[redis]/etc/pki/tls/certs/redis.pem")
modparam("tls_mgm", "private_key", "[redis]/etc/pki/tls/private/redis.key")
modparam("tls_mgm", "ca_list",     "[redis]/etc/pki/tls/certs/ca.pem")
...
modparam("cachedb_redis", "use_tls", 1)
modparam("cachedb_redis", "cachedb_url","redis://localhost:6379/?tls_domain=redis")
...
</programlisting>
		</example>
	</section>

	</section>


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

	<section>
	<title>Raw Query Syntax</title>
		<para>
			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.
		</para>

		<para>
			Here are a couple examples of running some Redis queries :
			<example>
			<title>Redis Raw Query Examples</title>
			<programlisting format="linespecific">
...
	$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","HGET $var(my_hash) $var(my_key)","$avp(result)");
	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","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");
		$var(it) = $var(it) + 1;
	}
...
			</programlisting>
			</example>
		</para>

	</section>


</chapter>

