StackExchange.Redis阻止流行设计

时间:2016-03-03 18:04:55

标签: c# stackexchange.redis

所以我们有一个现有的Helper库,它使用ServiceStack.Redis并且当前正在尝试将它与StackExchange.Redis交换。我们使用的是BlockingPop(BLPOP)但由于StackExchange.Redis不支持它。我们按如下方式实施了

public static void Push(string Qname, string val)
{
    IDatabase db = redis.GetDatabase();
    db.ListLeftPush(Qname, val);
    ISubscriber sub = redis.GetSubscriber();
    sub.Publish(Qname + "_msg", "1");
}

并使用阻止选项弹出如下:

    public static string Pop(string Qname, 
    bool block_until_available = false,int timeout_secs=0)
{   
    IDatabase db = redis.GetDatabase();            
    var popped = db.ListRightPop(Qname);
    if (popped.IsNull)
    {
        if (block_until_available == false)
            return null;
    }
    else
        return popped;

    //wait for an item to be pushed in.
    ISubscriber sub = redis.GetSubscriber();
    AutoResetEvent autoEvent = new AutoResetEvent(false);
    string obj = null;
    Task.Run(() =>
    {
        sub.Subscribe(Qname + "_msg", (channel, message) =>
        {
            popped = db.ListRightPop(Qname);
            if (!popped.IsNull)
            {
                obj = popped;
                sub.Unsubscribe(Qname + "_msg");
                autoEvent.Set();
            }
        });
    });
    if (timeout_secs > 0)
        autoEvent.WaitOne(timeout_secs * 1000);
    else
        autoEvent.WaitOne();
    return obj;
}

你们都看到这种方法有任何明显的问题吗?

另外,我很快遇到了以下错误。我增加了syncTimeout。希望能解决这个问题吗?

System.TimeoutException: Timeout performing RPOP DL_PROD, 
inst: 0, mgr: ProcessReadQueue, err: never, queue: 0, qu: 0, qs: 0, qc: 0, 
wr: 0, wq: 0, in: 0, ar: 1, IOCP: (Busy=0,Free=1000,Min=8,Max=1000), 
WORKER: (Busy=2,Free=32765,Min=8,Max=32767), 
clientName: CD147RE1 at 
StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl[T]
(Message message, ResultProcessor`1 processor, ServerEndPoint server) 

1 个答案:

答案 0 :(得分:2)

没有具体原因RPOP应该在这里超时,除非它与带宽有关(巨大的有效载荷)。该错误看起来与IMO问题无关。这个方法很难看,但是......好吧,它可能有用。但是,这里不需要使用Task.Run。我认为,这种方法的一个问题是它不会同时正常工作。它似乎取消订阅该频道/连接的所有代表,而不仅仅是那个。自我取消订阅是可能的,但坦率地说,我想知道是否更容易只有一个自动重置事件和单个订阅,并且如果一条消息在您等待时解锁了门:伟大

自我取消订阅代表的一般模式基本上是:

YourDelegateType handler = null;
handler = (args) => {
    DoTheThing();
    UnSubscribe(handler);
};
Subscribe(handler);

这使用词法捕获变量的乐趣来提供对委托中内部委托实例的访问,这意味着委托可以将本身传递给unsubscribe方法。上面显示的模式应适用于所有基于委托的回调方案 - 包括规范事件和SE.Redis发布/子处理程序等事项。