Я пытаюсь переупорядочить события, поступающие неупорядоченными на разные потоки.
Возможно ли создать запрос реактивного расширения, соответствующий этим мраморным диаграммам:
s1 1 2 3 4
s2 1 3 2 4
result 1 2 3 4
и...
s1 1 2 3 4
s2 4 3 2 1
result 1234
То есть: публиковать результаты только в порядке номеров версий.
Самое близкое, что у меня есть, - это использовать Join, чтобы открывать окно каждый раз, когда s1 тикает, и только закрывайте его, когда s2 приходит с тем же номером.
Вот так:
var publishedEvents = events.Publish().RefCount();
publishedEvents.Join(
publishedEvents.Scan(0, (i, o) => i + 1),
expectedVersion => publishedEvents.Any(@event => @event.Version == expectedVersion),
_ => Observable.Never<Unit>(),
(@event, expectedVersion) => new {@event,expectedVersion})
.Where(x => x.expectedVersion == [email protected])
.Select(x => [email protected])
.Subscribe(Persist);
Но это не сработает с диаграммой № 2. Группа 2 будет завершена после того, как s2 тикает с номером 2 и, следовательно, до 1.
Имеет ли смысл? Можно ли это сделать с помощью Rx? Должен ли он?
EDIT: Я думаю, что это похоже на перекрывающиеся окна, где более поздние окна не могут закрываться до закрытия всех предыдущих окон. И предыдущие окна не будут закрыты, пока номер окна не будет соответствовать номеру версии события.
ИЗМЕНИТЬ 2:
У меня сейчас что-то вроде этого, но на самом деле это не реактивное, функциональное, потокобезопасное LINQ-откровение, которое я надеялся (пожалуйста, проигнорируйте, что мои события JObjects пока):
var orderedEvents = Observable.Create<JObject>(observer =>
{
var nextVersionExpected = 1;
var previousEvents = new List<JObject>();
return events
.ObserveOn(Scheduler.CurrentThread)
.Subscribe(@event =>
{
previousEvents.Add(@event);
var version = (long) @event["Version"];
if (version != nextVersionExpected) return;
foreach (var previousEvent in previousEvents.OrderBy(x => (long) x["Version"]).ToList())
{
if ((long) previousEvent["Version"] != nextVersionExpected)
break;
observer.OnNext(previousEvent);
previousEvents.Remove(previousEvent);
nextVersionExpected++;
}
});
});