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)))
)