title: Redis BookSleeve socket exhaustion
body: <p>I'm receiving a SocketException when using BookSleeve to connect and add/get entries to/from my Redis server. The specific exception is: <strong>Only one usage of each socket address (protocol/network address/port) is normally permitted.</strong> </p>
  
  <p>The stack trace points to: <code>BookSleeve.RedisConnectionBase.Wait(Task task) in d:\Dev\BookSleeve\BookSleeve\RedisConnectionBase.cs:2050</code></p>
  
  <p>My question is whether I'm doing something wrong in my code (highly likely) that isn't properly closing connections or something of that nature? The exception tends to be thrown after ~16000 operations or so are performed in about 60 seconds. That doesn't seem like an overly abundant amount of operations, right?</p>
  
  <p>Relevant code is below and I'm happy to provide any other information.</p>
  
  <pre><code>public Cache.CacheEntry Get(string key, bool updateAccessed)
  {
      var cacheKey = GetCacheableKey(key);    
  
      using (var conn = GetUnsecuredConnection())
      {
          var entry = conn.Get&lt;Cache.CacheEntry&gt;(cacheKey);
          return entry;
      }
  }
  
  public override void Add(string key, Cache.CacheEntry entry)
  {
      var cacheKey = GetCacheableKey(key);    
  
      using (var conn = GetUnsecuredConnection())
      {
          using (var trans = conn.CreateTransaction())
          {
              trans.Set(cacheKey, entry);
              trans.Strings.Increment(DbNum, CacheEntryCountKey);
              trans.Strings.Increment(DbNum, CacheSizeKey, entry.DataLength);
              trans.Sets.Add(DbNum, CacheKeysKey, cacheKey);
              trans.Execute();
          }
      }
  }
  </code></pre>
  
  <p>Retrieving a connection (this was largely copied from the BookSleeve unit tests:</p>
  
  <pre><code>protected RedisConnection GetUnsecuredConnection(bool open = true, bool allowAdmin = false, bool waitForOpen = false)
  {
      var host = ConfigurationManager.AppSettings["Redis.BookSleeve.Host"];
      var unsecuredPort = int.Parse(ConfigurationManager.AppSettings["Redis.BookSleeve.UnsecuredPort"]); //TODO: get this setting in a safer manner
  
      var conn = new RedisConnection(host, unsecuredPort, syncTimeout: 5000, ioTimeout: 5000, allowAdmin: allowAdmin);
      conn.Error += (s, args) =&gt; Log.Error(args.Exception.Message + args.Cause, args.Exception, typeof(RedisProviderBookSleeve));
      if (open)
      {
          var openAsync = conn.Open();
          if (waitForOpen) conn.Wait(openAsync);
      }
      return conn;
  }
  </code></pre>
  
  <p>Generic extension methods for the RedisConnection object:</p>
  
  <pre><code>public static T Get&lt;T&gt;(this RedisConnection conn, string key, int dbNum = 0)
  {
      if (typeof (T) == typeof (byte[]))
      {
          var task = conn.Strings.Get(dbNum, key);
          var result = conn.Wait(task);
          return (T) (object) result;
      }
      else
      {
          var task = conn.Strings.GetString(dbNum, key);
          var result = conn.Wait(task);
          if (result == null || typeof(T) == typeof(string))
              return (T)(object)result;
  
          return JsonSerializer.DeserializeFromString&lt;T&gt;(result);
      }
  }
  
  
  public static void Set&lt;T&gt;(this RedisConnection conn, string key, T value, int dbNum = 0)
  {
      if (typeof (T) == typeof (byte[]))
      {
          conn.Strings.Set(dbNum, key, value as byte[]);
          return;
      }
  
      var serializedValue = JsonSerializer.SerializeToString(value);
      conn.Strings.Set(dbNum, key, serializedValue);
  }
  </code></pre>