c# - password - Mantener una conexión abierta de Redis usando BookSleeve
stackexchange redis pipeline example (3)
Con otros sistemas (como ADO.NET), esto se logra usando un grupo de conexiones. En realidad, nunca obtienes un nuevo objeto Connection, sino que obtienes uno del grupo.
El grupo en sí administra las conexiones nuevas y las conexiones muertas, independientemente del código de la persona que llama. La idea aquí es tener un mejor rendimiento (establecer una nueva conexión es costoso), y sobrevivir a los problemas de red (el código de la persona que llama fallará mientras el servidor está caído pero se reanudará cuando vuelva a estar en línea). De hecho, hay un grupo por AppDomain, por "tipo" de conexión.
Este comportamiento ocurre cuando observa cadenas de conexión ADO.NET. Por ejemplo, la cadena de conexión de SQL Server ( Propiedad ConnectionString ) tiene la noción de ''Pooling'', ''Max Pool Size'', ''Min Pool Size'', etc. Este es también un método ClearAllPools que se usa para reiniciar programáticamente los pools de AppDomain actuales si es necesario por ejemplo.
No veo nada parecido a este tipo de características en el código BookSleeve, pero parece estar planificado para la próxima versión: BookSleeve RoadMap .
Mientras tanto, supongo que puedes escribir tu propio grupo de conexiones ya que RedisConnection tiene un evento de error que puedes usar para esto, para detectar cuándo está muerto.
¿Alguien tiene un patrón sólido de búsqueda de Redis a través de la biblioteca BookSleeve ?
Quiero decir:
El autor de BookSleeve @MarcGravell recomienda no abrir y cerrar la conexión cada vez, sino mantener una conexión en toda la aplicación. Pero, ¿cómo puedes manejar los cortes de red? es decir, la conexión podría abrirse con éxito en primer lugar, pero cuando algún código intente leer / escribir en Redis, existe la posibilidad de que la conexión haya caído y usted deba volver a abrirla (y fallar con gracia si no se abre, pero eso depende de sus necesidades de diseño).
Busco fragmento (s) de código que cubra la apertura general de la conexión Redis, y una verificación general ''activa'' (+ despertador opcional si no está vivo) que se usaría antes de cada lectura / escritura.
Esta pregunta sugiere una actitud agradable hacia el problema, pero es solo parcial (no recupera una conexión perdida, por ejemplo), y la respuesta aceptada a esa pregunta dibuja el camino correcto pero no muestra un código concreto.
Espero que este hilo obtenga respuestas sólidas y eventualmente se convierta en una especie de Wiki con respecto al uso de BookSleeve en aplicaciones .Net.
-----------------------------
ACTUALIZACIÓN IMPORTANTE (21/3/2014):
-----------------------------
Marc Gravell (@MarcGravell) / Stack Exchange han lanzado recientemente la biblioteca StackExchange.Redis que finalmente reemplaza a Booksleeve. Esta nueva biblioteca, entre otras cosas, maneja internamente las reconexiones y hace que mi pregunta sea redundante (es decir, no es redundante para Booksleeve ni para mi respuesta a continuación, pero creo que la mejor manera de seguir adelante es comenzar a utilizar la nueva biblioteca StackExchange.Redis).
No soy un programador de C #, pero la forma en que vería el problema es la siguiente:
Codificaría una función genérica que tomaría como parámetros la conexión redis y una expresión lambda que representa el comando Redis
si tratar de ejecutar el comando Redis daría como resultado una excepción que indica un problema de conectividad, reiniciaré la conexión y volveré a intentar la operación
si no se presenta ninguna excepción, solo devuelva el resultado
Aquí hay algún tipo de pseudo-código:
function execute(redis_con, lambda_func) {
try {
return lambda_func(redis_con)
}
catch(connection_exception) {
redis_con = reconnect()
return lambda_func(redis_con)
}
}
Como no tengo buenas respuestas, se me ocurrió esta solución (por cierto, gracias @Simon y @Alex por sus respuestas).
Quiero compartirlo con toda la comunidad como referencia. Por supuesto, cualquier corrección será muy apreciada.
using System;
using System.Net.Sockets;
using BookSleeve;
namespace Redis
{
public sealed class RedisConnectionGateway
{
private const string RedisConnectionFailed = "Redis connection failed.";
private RedisConnection _connection;
private static volatile RedisConnectionGateway _instance;
private static object syncLock = new object();
private static object syncConnectionLock = new object();
public static RedisConnectionGateway Current
{
get
{
if (_instance == null)
{
lock (syncLock)
{
if (_instance == null)
{
_instance = new RedisConnectionGateway();
}
}
}
return _instance;
}
}
private RedisConnectionGateway()
{
_connection = getNewConnection();
}
private static RedisConnection getNewConnection()
{
return new RedisConnection("127.0.0.1" /* change with config value of course */, syncTimeout: 5000, ioTimeout: 5000);
}
public RedisConnection GetConnection()
{
lock (syncConnectionLock)
{
if (_connection == null)
_connection = getNewConnection();
if (_connection.State == RedisConnectionBase.ConnectionState.Opening)
return _connection;
if (_connection.State == RedisConnectionBase.ConnectionState.Closing || _connection.State == RedisConnectionBase.ConnectionState.Closed)
{
try
{
_connection = getNewConnection();
}
catch (Exception ex)
{
throw new Exception(RedisConnectionFailed, ex);
}
}
if (_connection.State == RedisConnectionBase.ConnectionState.Shiny)
{
try
{
var openAsync = _connection.Open();
_connection.Wait(openAsync);
}
catch (SocketException ex)
{
throw new Exception(RedisConnectionFailed, ex);
}
}
return _connection;
}
}
}
}