Application requirements:
This should work. The types differ, I didn't want to guess your probably abstract datatypes. You can apply them pretty easily (function parameters, key comparison and Select
statements)
Idea is that for every emited value from a
, we take the first value emited either by b.Where(keys match)
or timeout (presented by Observable.Timer
) and make our Select
based on this information.
I assumed that in timeout cases you also want on OnNext
notification with some error provisioning mechanism.
private IObservable<string> MonitorAB(IObservable<long> a, IObservable<long> b,
TimeSpan threshold)
{
return Observable.Create<string>((obs) =>
{
a = a.Publish().RefCount();
b = b.Publish().RefCount();
return a.Subscribe(i =>
{
Observable.Merge(Observable.Timer(threshold).Select(_ => $"Timeout for A{i}"),
b.Where(j => j == i).Select(_ => $"Got matching B for A{i}"))
.Take(1)
.Subscribe(obs.OnNext);
});
});
}
I tested it like this.
private void Test()
{
var a = Observable.Interval(TimeSpan.FromSeconds(2)).Take(5);
var b = Observable.Interval(TimeSpan.FromSeconds(5)).Take(5);
MonitorAB( a, b, TimeSpan.FromSeconds(13)).Subscribe(Console.WriteLine);
}
EDIT: to test the out of order case, you can flip the B stream e.g.
var b = Observable.Interval(TimeSpan.FromSeconds(2)).Select(i => 4 - i).Take(5);
I think this does what you want, albeit it is C# rather than Java - I'm sure you can convert easily enough.
private IObservable<string> MonitorAB(
IObservable<long> a, IObservable<long> b, TimeSpan threshold)
{
return Observable.Create<string>(o =>
b.Publish(pb =>
a.Select(ax =>
pb.Where(pbx => pbx == ax)
.Take(1)
.Timeout(threshold, Observable.Return(-1L))
.Select(pbx => String.Format("{0},{1}", ax, pbx)))
.Merge())
.Subscribe(o));
}
So this simply uses the inline .Publish
to make sure b
is hot within the query. The outer .Select
filters the published pb
observable for those that match the value from a
(matching a
& b
), takes only one cause we only want one, and then does a .Timeout
for the threshold
time and returns a -1L
(long
) if the timeout is reached. The inner .Select
just turns the two long
values into a single string
. At this point the query is an IObservable<IObservable<string>>
so the .Merge
flattens it out.
Assumptions:
Then this would be fine.
AStream.SelectMany(a =>
BStream.Where(b => b == a)
.Select(b => new MatchMade(a, b))
.Take(1)
.Timeout(matchTimeout)
.Catch<TimeoutException>(ex=>Observable.Return(new NoMatchMade(a)))
)