0

使用 BookSleeve 连接我的 Redis 服务器并向/从我的 Redis 服务器添加/获取条目时,我收到一个 SocketException。具体的例外是:每个套接字地址(协议/网络地址/端口)通常只允许使用一次。

堆栈跟踪指向:BookSleeve.RedisConnectionBase.Wait(Task task) in d:\Dev\BookSleeve\BookSleeve\RedisConnectionBase.cs:2050

我的问题是我是否在我的代码中做错了什么(很可能)没有正确关闭连接或类似的东西?在大约 60 秒内执行约 16000 次操作后,往往会引发异常。这似乎不是一个过于丰富的操作,对吧?

相关代码如下,我很乐意提供任何其他信息。

public Cache.CacheEntry Get(string key, bool updateAccessed)
{
    var cacheKey = GetCacheableKey(key);    

    using (var conn = GetUnsecuredConnection())
    {
        var entry = conn.Get<Cache.CacheEntry>(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();
        }
    }
}

检索连接(这主要是从 BookSleeve 单元测试中复制的:

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) => Log.Error(args.Exception.Message + args.Cause, args.Exception, typeof(RedisProviderBookSleeve));
    if (open)
    {
        var openAsync = conn.Open();
        if (waitForOpen) conn.Wait(openAsync);
    }
    return conn;
}

RedisConnection 对象的通用扩展方法:

public static T Get<T>(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<T>(result);
    }
}


public static void Set<T>(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);
}
4

1 回答 1

1

Marc 对这个问题的评论让我重新考虑我是如何利用连接的。我遇到了另一个问题的答案:

使用 BookSleeve 维护打开的 Redis 连接

我最终使用了上述链接答案中的代码,删除了我发布的“GetUnsecuredConnection”方法,现在只需在构造/执行 Redis 操作之前检索打开的连接。

不再有 SocketException,一切似乎都按预期运行。感谢马克的提示!感谢@ofer-zelig 提供的连接代码。

public Cache.CacheEntry Get(string key, bool updateAccessed)
{
    var cacheKey = GetCacheableKey(key);    

    var conn = RedisConnectionGateway.Current.GetConnection();

    var entry = conn.Get<Cache.CacheEntry>(cacheKey);
    return entry;        
}

public override void Add(string key, Cache.CacheEntry entry)
{
    var cacheKey = GetCacheableKey(key);    

    var conn = RedisConnectionGateway.Current.GetConnection();

    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();
    }        
}
于 2014-01-02T17:05:06.153 回答