Mantenimento di una connessione Redis aperta utilizzando BookSleeve

Qualcuno ha uno schema solido che recupera Redis tramite la libreria BookSleeve ?

Intendo:

L’autore di BookSleeve @MarcGravell consiglia di non aprire e chiudere la connessione ogni volta, ma di mantenere una connessione in tutta l’app. Ma come puoi gestire le interruzioni di rete? cioè la connessione potrebbe essere aperta con successo in primo luogo, ma quando un codice prova a leggere / scrivere su Redis, c’è la possibilità che la connessione sia caduta e tu devi riaprirla (e fallire con grazia se non si apre), ma questo dipende dalle tue esigenze di progettazione.)

Cerco frammenti di codice che coprano l’apertura generale della connessione Redis e un controllo generale “vivo” (+ opzionale sveglio se non vivo) che sarebbe usato prima di ogni lettura / scrittura.

Questa domanda suggerisce una buona attitudine al problema, ma è solo parziale (non recupera una connessione persa, per esempio), e la risposta accettata a quella domanda disegna la strada giusta ma non dimostra un codice concreto.

Spero che questo thread otterrà solide risposte e alla fine diventerà una sorta di Wiki per quanto riguarda l’utilizzo di BookSleeve nelle applicazioni .Net.

—————————–

AGGIORNAMENTO IMPORTANTE (21/3/2014):

—————————–

Marc Gravell (@MarcGravell) / Stack Exchange ha recentemente rilasciato la libreria StackExchange.Redis che alla fine sostituisce Booksleeve. Questa nuova libreria, tra le altre cose, gestisce internamente le riconnessioni e rende ridondante la mia domanda (cioè non è ridondante per Booksleeve né la mia risposta sotto, ma immagino che il modo migliore per andare avanti sia iniziare a utilizzare la nuova libreria StackExchange.Redis).

Dal momento che non ho avuto buone risposte, ho trovato questa soluzione (BTW ringrazia @Simon e @Alex per le tue risposte!).

Voglio condividerlo con tutta la comunità come riferimento. Naturalmente, eventuali correzioni saranno molto apprezzate.

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; } } } } 

Con altri sistemi (come ADO.NET), questo viene ottenuto utilizzando un pool di connessioni. Non si ottiene mai realmente un nuovo object Connection, ma in effetti ne viene ottenuto uno dal pool.

Il pool stesso gestisce nuove connessioni e connessioni non funzionanti, indipendentemente dal codice del chiamante. L’idea è di avere prestazioni migliori (stabilire una nuova connessione è costosa) e sopravvivere ai problemi di rete (il codice del chiamante fallirà mentre il server è inattivo ma riprenderà quando ritorna online). Esiste infatti un pool per AppDomain, per “tipo” di connessione.

Questo comportamento si verifica quando si guardano le stringhe di connessione ADO.NET. Ad esempio, la stringa di connessione di SQL Server ( ConnectionString Property ) ha la nozione di “Pooling”, “Max Pool Size”, “Min Pool Size”, ecc. Questo è anche un metodo ClearAllPools che viene utilizzato per reimpostare programmaticamente gli attuali pool di AppDomain, se necessario per esempio.

Non vedo nulla di simile a questo tipo di funzionalità che esamina il codice BookSleeve, ma sembra che sia pianificato per la prossima versione: BookSleeve RoadMap .

Nel frattempo, suppongo che tu possa scrivere il tuo pool di connessione poiché RedisConnection ha un evento di errore che puoi usare per questo, per rilevare quando è morto.

Non sono un programmatore C #, ma il modo in cui guarderei il problema è il seguente:

  1. Codificherei una funzione generica che avrebbe come parametri la connessione redis e un’espressione lambda che rappresenta il comando Redis

  2. se provando ad eseguire il comando Redis si tradurrebbe in un’eccezione che segnala un problema di connettività, ho re-inizializzato la connessione e riprovo l’operazione

  3. se non viene sollevata alcuna eccezione, basta restituire il risultato

Ecco una sorta di pseudo-codice:

 function execute(redis_con, lambda_func) { try { return lambda_func(redis_con) } catch(connection_exception) { redis_con = reconnect() return lambda_func(redis_con) } }