使用Rx超时与FromEventPattern Observer

时间:2013-11-19 15:29:50

标签: c# events timeout system.reactive

我正在尝试在一段时间内没有事件时实现超时。

情景:

我有一个对象,每次收到消息时都会引发一个事件。 我希望在一段时间内没有收到消息(OnReceived events)(比方说,20秒)时作出反应

这是我到目前为止所拥有的

var observable =  Observable.FromEventPattern<BasicDeliverEventHandler>(
                             handler => _innerConsumer.Received += OnReceived,
                             handler => _innerConsumer.Received -= OnReceived);

var timeout = observable.Timeout(TimeSpan.FromSeconds(20));
using (timeout.Subscribe(_ => { },
              exception => 
              Tracer.Warning("Eventing Consumer timeout : {0}", exception.Message)))
{ }

我正在从EventPattern创建一个observable。然后,使用超时。我不明白的是如何从超时中获取异常。我希望在发生这种情况时做出反应。

我不认为Subcribe方法是正确的方法,但我从文档中得到了。   如果这不是正确的话,我愿意接受建议或其他选择。

提前致谢

2 个答案:

答案 0 :(得分:3)

Timeout有问题,因为它会终止序列。 Throttle是您想要的 - 但您还需要插入一个start元素,以防万一没有任何事件。

我将事件转换为Unit.Default - 当你不关心发生了什么事情时,这很有用,只是发生了某事 - 并且使用StartWith来设置节流:

var timeout = observable.Select(_ => Unit.Default)
                        .StartWith(Unit.Default)
                        .Throttle(TimeSpan.FromSeconds(20);

var subs = timeout.Subscribe(_ => Console.WriteLine("Timeout!"));

出于兴趣,我也有一个类似的解决方案,用于检测断开的客户端 - 这次为多个来源提供单个超时通知:http://www.zerobugbuild.com/?p=230

答案 1 :(得分:1)

让我们来看看你的代码。

var observable =
  Observable.FromEventPattern<BasicDeliverEventHandler>(
    handler => _innerConsumer.Received += OnReceived,
    handler => _innerConsumer.Received -= OnReceived
    );

var timeout = observable.Timeout(TimeSpan.FromSeconds(20));

using (timeout.Subscribe(
  _ => { },
  exception =>
  Tracer.Warning("Eventing Consumer timeout : {0}", exception.Message)))
{

}

我们可以像这样重写订阅逻辑:

var subscription = timeout.Subscribe(
  _ => { }
  exception =>
    Tracer.Warning("Eventing Consumer timeout : {0}", exception.Message)
  );

subscription.Dispose(); // This is bad

由于您的订阅被立即处理,您的观察者没有收到您期望的通知。

删除subscription.Dispose()using语句后,您的观察者应在订阅后20秒内收到TimeoutException。但是,由于Exception也取消了订阅,因此您只会收到此Exception一次。

此外,Timeout运算符在订阅时启动超时,除非取消订阅或源观察者完成,否则不会取消超时。

您可能想尝试使用其他运算符,例如Throttle

observable.Throttle(TimeSpan.FromSeconds(20))
    .Subscribe(x =>
        Console.WriteLine("it has been 20 seconds since we received the last notification.")
        )