Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Использование времени ожидания Rx с наблюдателем FromEventPattern

Автор вопроса: MarcoteОтветов: 2

Я пытаюсь реализовать тайм-аут, когда за период времени нет событий.

Сценарий:

У меня есть объект, который вызывает событие каждый раз при получении сообщения. Я хотел бы реагировать, когда нет сообщений (событий OnReceived), полученных в течение определенного периода времени (скажем, 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. Затем, используя тайм-аут. Чего я не понимаю, так это того, как получить исключение из тайм-аута. Я хочу реагировать, когда это происходит.

Я не думаю, что метод подписки является правильным, но это я понял из документации. Я открыт для предложений или других альтернатив, если это не правильно.

заранее спасибо

  • В вашем коде не должно быть оператора using. Это немедленно отменяет вашу подписку, что не позволяет вашим уведомлениям достигать наблюдателя. cwharris 19.11.2013

eventstimeout

Ответы

Ответ 1 · рейтинг 3 · James World

Timeout проблематичен, потому что он завершает последовательность. Throttle - это то, что вам нужно, но вам также нужно вставить начальный элемент на случай, если вы вообще не получите никаких событий.

Я преобразовываю события в 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

Ответ 2 · рейтинг 1 · cwharris

Давайте посмотрим на код, который у вас есть.

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, ваш наблюдатель должен получить TimeoutException через 20 секунд после подписки. Однако, поскольку Exception также отменяет подписку, вы получите это Exception только один раз.

Кроме того, оператор Timeout запускает тайм-аут во время подписки и не отменяет тайм-аут, пока подписка не будет отменена или не завершится исходный наблюдатель.

Вы можете попробовать использовать другой оператор, например Throttle.

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы