我想确保我的Rx通知在与我的消费者Do
代表进行处理后不会丢失。我有一个Producer,它生成我需要处理的消息,如果失败则重试处理。
理想的大理石图:
Producer 1 2 3 4 5
Consumer 1 X 2 3 X X 4 5
Downstream 1 2 3 4 5
标准Retry
在这里没有帮助,因为它会在发生错误后重新订阅制作人。这将丢失处理失败的通知,并继续下一个通知。
Retry
大理石图:
Producer 1 2 3 4 5
Consumer 1 X 3 X 5
到目前为止,我有这段代码,但它对我来说似乎不对:
static void RetryWithBacklog()
{
var data = Enumerable.Range(1, 100).ToObservable();
var backlog = new Subject<long>();
backlog
.Merge(data)
.Retry()
.Do(l =>
{
try
{
ProcessNotification(l);
}
catch (Exception)
{
backlog.OnNext(l);
}
})
.Subscribe();
Console.ReadKey();
}
Do
操作将根据制作人的通知执行网络请求。这些可能会失败,所以我需要重试它而不会丢失要传输的信息。当然,我可以盲目while try/catch
网络请求,但只要知道网络连接已关闭,请求就不会发生(请参阅this question)。
static void RetryBeforePassingDownstream()
{
var data = Enumerable.Range(1, 100).ToObservable();
data
.Replay(l => l.SelectMany(ProcessNotification).Retry(), 1)
.Subscribe(Downstream);
Console.ReadKey();
}
static IObservable<int> ProcessNotification(int notification)
{
Console.WriteLine("process: {0}", i);
// either:
// throw new Exception("error");
// or:
return Observable.Return(notification);
}
static void Downstream(int i)
{
Console.WriteLine("downstream: {0}", i);
}
答案 0 :(得分:1)
Retry
运算符的意思是它通过重新订阅在冷可观察量上工作,因此每次“重试”时都会导致订阅副作用。例如,您的observable可能会在每次观察者订阅时发送Web请求。在您的示例中,Retry
运算符没有任何意义,特别是考虑到Interval
从不调用OnError
。
Retry
语义在技术上可以分别存在于observable和观察者中。在您的情况下,您是否只需致电ProcessNotification
,直到Do
运营商成功为止?
或者问题只是下游观察员在Do
投掷时不会观察到通知?我猜这不是你的意思,因为在这种情况下你可以简单地吞下异常。
或者您的问题是,如果要重播通知,通知可能会以某种方式发生变化或被上游运营商过滤掉?在这种情况下,您可能只需使用Do
后跟Catch
和递归来实现同样的事情而不需要Subject
,但我无法弄清楚为什么你真的想要这样做。
<强>更新强>
Do
运算符不是异步的。请改用SelectMany
,以便它成为您查询的一部分。这样,取消订阅也将取消该请求。如果您的请求方法返回Task<T>
而不是IObservable<T>
,那么请考虑使用接受CancellationToken
的重载。
有一种更简单的方法可以使 cold observable重放上一个通知,只需使用Retry
运算符即可重试,如下所示。
(未测试的)
data.Replay(r => r.YourStateMachine.SelectMany(SendRequestAsync).Retry(), 1);
詹姆斯的回答here可以填写 YourStateMachine 。