我正在尝试使用Oracle AQ的Reactive扩展。当Oracle Queue上出现消息时,它会触发" OracleAQMessageAvailableEvent"告诉消费者有消息。在OracleAQMessageAvailableEventHandler中,使用者调用OracleAQQueue.Dequeue()来检索消息。
我已经完成了以上的RX工作。以下是我使用过的代码。
var messages = Observable.FromEventPattern<OracleAQMessageAvailableEventHandler, OracleAQMessageAvailableEventArgs> (
h => _queue.MessageAvailable += h, h => _queue.MessageAvailable -= h)
.Where(x => x.EventArgs.AvailableMessages > 0)
.Select(x =>
{
OracleAQMessage msg = _queue.Dequeue();
return (UpdateMsg) msg.Payload;
});
messages.subscribe(....)
问题是,如果我订阅了一切,但是如果我多次订阅消息(即我的应用程序中有多个消费者),那么每个消费者都会尝试调用&#34; _queue.Dequeue()&#34;如果我们没有新消息,第一次通话后的每次通话都将失败。
有人可以指导我该怎么做。我想,我的场景是针对Hot Observable,但我很难理解它。
答案 0 :(得分:3)
我认为你正在寻找一个Hot Observable是正确的。
如果我们遵循代码,可能会更清楚为什么您会多次调用_queue.Dequeue();
。
首先,您订阅Oracle的活动
Observable.FromEventPattern<OracleAQMessageAvailableEventHandler, OracleAQMessageAvailableEventArgs> (
h => _queue.MessageAvailable += h,
h => _queue.MessageAvailable -= h)
这就像挂接前Rx世界中的事件处理程序一样。 每个人听(订阅)都会收到相同的事件。 如果他们在提出事件后订阅,那么他们就错过了。
然后你过滤掉空集。
.Where(x => x.EventArgs.AvailableMessages > 0)
那里没什么特别的。
然后从查询中执行副作用。
.Select(x =>
{
OracleAQMessage msg = _queue.Dequeue();
return (UpdateMsg) msg.Payload;
});
这里的副作用是您正在进行破坏性阅读(Dequeue
)。
所有订阅者从上游_queue.MessageAvailable
推送活动时都会尝试拨打Dequeue()
。
为避免所有订阅者调用副作用,您可以将序列设为Hot(如您所建议的那样)。
为此,您可以查看Publish()
运算符。
Publish()
运算符会通过添加IConnectableObservable<T>
方法向您返回IObservable<T>
,只展开Connect()
。
这允许对订阅逻辑执行时进行细粒度控制。
但是,这对你来说可能有太多的控制,你可能会发现RefCount()
正是你所需要的。
Observable.FromEventPattern<OracleAQMessageAvailableEventHandler, OracleAQMessageAvailableEventArgs> (
h => _queue.MessageAvailable += h,
h => _queue.MessageAvailable -= h)
.Where(x => x.EventArgs.AvailableMessages > 0)
.Select(x =>
{
OracleAQMessage msg = _queue.Dequeue();
return (UpdateMsg) msg.Payload;
})
.Publish()
.Refcount();
现在,您的每个订阅者都会收到相同的消息,并且每个事件只会调用一次Dequeue()
副作用(并且只有订阅者时才会调用)。
热和冷可观察到here
答案 1 :(得分:-1)
public IObservable<UpdateMsg> Messages {
get { return Observable.FromEventPattern<OracleAQMessageAvailableEventHandler, OracleAQMessageAvailableEventArgs> (
h => _queue.MessageAvailable += h,
h => _queue.MessageAvailable -= h)
.Where(x => x.EventArgs.AvailableMessages > 0)
.Select(x =>
{
OracleAQMessage msg = _queue.Dequeue();
return (UpdateMsg) msg.Payload;
})
.Publish()
.Refcount();
}}
我的客户端代码是使用Messages属性订阅的,如此
// First Subscription
_queueWrapper.Messages.Subscribe(....)
// Second Subscription
_queueWrapper.Messages.Subscribe(....)
因此,对于每个订阅,Messages属性都返回一个新的IObservable。为了解决这个问题,我将observable的初始化移到了QueueWrapper的构造函数,即代码:
public QueueWrapper() {
_messages = Observable.FromEventPattern<OracleAQMessageAvailableEventHandler, OracleAQMessageAvailableEventArgs> (
h => _queue.MessageAvailable += h,
h => _queue.MessageAvailable -= h)
.Where(x => x.EventArgs.AvailableMessages > 0)
.Select(x =>
{
OracleAQMessage msg = _queue.Dequeue();
return (UpdateMsg) msg.Payload;
})
.Publish()
.Refcount();
}
我的Messages属性只返回_messages;
public IObservable<UpdateMsg> Messages { get { return _messages; } }
之后,一切都按预期开始工作。