小编典典

ServiceStack.Redis无法读取传输-BasicRedisClientManager

redis

尝试通过ServiceStack.Redis读取Redis列表时,间歇性出现以下错误:“无法从传输连接读取数据:已建立的连接被主机中的软件中止了”。我想知道我如何使用ServiceStack可靠地连接和池化Redis的整个概念是否是错误的。这是我使用密封类和单例模式进行连接的代码:

public sealed class RedisClientBase
{
    public BasicRedisClientManager Redis;
    private static readonly RedisClientBase instance = new RedisClientBase();

    private RedisClientBase()
    {
        Redis = new BasicRedisClientManager("mypassword@localhost:6379");
    }

    public static RedisClientBase Instance
    {
        get
        {
            return instance;
        }
    }
}

然后,我实例化另一个使用单例的类:

public class RedisBarSetData
{
    private static RedisClient Redis;
    protected IRedisTypedClient<BarSet> redisBarSetClient;
    protected string instrument_key;

    public RedisBarSetData()
    {
        Redis = (RedisClient)RedisClientBase.Instance.Redis.GetClient();
        redisBarSetClient = Redis.As<BarSet>();
    }

    ~RedisBarSetData()
    {
        if (Redis != null)
            Redis.Dispose();
    }

    public List<BarSet> getData(BarSets data)
    {
        setKeys(data);  // instrument_key is set in here
        var redisBarSetClientList = redisBarSetClient.Lists[instrument_key];
        List<BarSet> barSetData;

        barSetData = redisBarSetClientList.GetAll();  // <-- exception here (sometimes)
        return(barSetData);
    }
}

这又是从“服务” DTO回调中实例化和调用的:

public class JmaSetsService : Service
{
    public object Get(JmaSets request)
    {
            RedisBarSetData barSetData = new RedisBarSetData();
            BarSets barSets = new BarSets(request);
            barSetList = barSetData.getData(barSets);
            return barSetList;
    }
}

然后,我使用“邮递员”发布到该路线。多数点击“发送”会返回数据。有些例外。例外是尝试从代码中以注释“
<-例外”指示的redis读取内容时。现在,另一点是,我最近通过设置配置文件将Redis配置为使用密码。我提到这一点是因为我之前不记得有这个问题,但这也不可能相关,不知道。

就释放Redis连接而言,我的想法是我的析构函数调用Redis。当RedisBarSetData()超出范围时处置。这是处理它的可靠方法还是有更好的方法?我看到有人在获得池化客户端时使用“
using”语句,但是我在类中只有一个地方有很多“ using”语句,而不是调用:“ Redis
=(RedisClient)RedisClientBase.Instance.Redis .GetClient();”
如果我有很多用于该类的方法,那么我必须在每个方法中重复执行代码吗?

  • 当我说“我以前不记得有这个问题”时,我正在将这种模式用于数十个工作的DTO。不确定为什么现在失败了吗?

阅读 387

收藏
2020-06-20

共1个答案

小编典典

您不应持有RedisClientIRedisTypedClient<BarSet>封装了非线程安全的Redis
TCP连接的任何单例实例。相反,您可以保留-的单例实例,IRedisClientsManager这是提供线程安全的Redis Client
Factory(如数据库连接池)的目的。

如果您还使用ServiceStack
Services,则在ServiceStack的IOC中注册依赖项会更容易,因此IRedisClientsManager可以像其他任何依赖项一样注入,例如AppHost.Configure()

container.Register<IRedisClientsManager>(c =>
    new BasicRedisClientManager("mypassword@localhost:6379"));

这将允许您base.Redis在ServiceStack Services中使用RedisClient属性,例如:

public class JmaSetsService : Service
{
    public object Get(JmaSets request)
    {
        var redisBarSets = base.Redis.As<BarSet>();
        return redisBarSets.Lists[instument_key].GetAll();
    }
}

如果您使用base.Redis,则不必显式处理RedisClient,因为它已经
由Service自动处理,即:

public class Service
{
    ...

    public virtual void Dispose()
    {
        if (redis != null)
            redis.Dispose();
        ...
    }
}

您还可以IRedisClientsManager像其他任何依赖项一样,使用公共属性或Constructor参数将其注入自己的类中,例如:

public class RedisBarSetData
{
    public virtual IRedisClientsManager RedisManager { get; set; }

    private IRedisClient redis;
    public virtual IRedisClient Redis
    {
        get { return redis ?? (redis = RedisManager.GetClient()); }
    }

    public override void Dispose()
    {
        if (redis != null)
            redis.Dispose();
    }

    public List<BarSet> getData(BarSets data)
    {
        setKeys(data);  // instrument_key is set in here
        return Redis.As<BarSet>().Lists[instrument_key].GetAll();
    }
}

然后,您可以使用以下方法在ServiceStack的IOC中进行注册和自动连线:

container.RegisterAutoWired<RedisBarSetData>();

然后,您可以将其用作服务中的依赖项:

public class JmaSetsService : Service
{
    public RedisBarSetData RedisBarSetData { get; set; }

    public object Get(JmaSets request)
    {
        return RedisBarSetData.getData(new BarSets(request));
    }
}

创建您自己的基类的一种替代方法是从预先存在的LogicBase基类继承,该基类已经具有IRedisClientsManager属性并且位于样板之上。

2020-06-20