Я пишу службу, которая в основном синхронизирует 2 источника данных. Требования состоят в том, что он периодически синхронизируется, но также возможно, чтобы администратор вручную запускал его для синхронизации в ответ на определенные случаи.
Мы используем сообщения MassTransit для IPC, поэтому веб-интерфейс отправит (скажем) TriggerSyncMessage через MassTransit, и служба увидит их.
Затем, используя реактивные расширения, мы подписываемся на сообщение MT, и мы настраиваем также наблюдаемый таймер, чтобы реагировать на это - отлично.
Но тогда, поскольку эти наблюдаемые имеют разные типы, мы не можем их объединить(). Мы хотим, чтобы оба (повторных) действия запускали одно и то же (синхронизирующее вещество), поэтому я в настоящее время использую объект, чтобы связать 2 наблюдаемых вместе, и затем я подписываюсь на это для последней части.
Вот так:
var syncMessageObserver = Bus.Instance.AsObservable<TriggerSyncMessage>();
var subject = new Subject<string>();
syncMessageObserver.Subscribe(msg =>
{
subject.OnNext("from message");
});
var timerSyncer = Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(60000)).Timestamp();
timerSyncer.Subscribe(x =>
{
subject.OnNext("from timer");
});
subject.AsObservable().Subscribe(msg =>
{
// actual syncing stuff
});
У меня есть 2 вопроса по этому подходу: 1. Является ли это... правильным способом справиться с этим делом? Я не уверен, что вы хотите использовать предмет, чтобы связать наблюдаемые вместе, или если есть лучший способ.
Первая часть выглядит достаточно разрешимой. Просто игнорируйте значения и проецируйте свое сообщение. Здесь мы используем шаблон именования игнорируемого параметра '_' (который является допустимым именем переменной С#).
//TODO: Rename syncMessageObserver. It is not an Observer, it is an Observable.
Observable.Merge(
syncMessageObserver.Select(_ => "from message"),
Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(60000)).Timestamp().Select( _=> "from timer")
)
.Subscribe(msg =>
{
// actual syncing stuff
});
Следующая проблема немного, но сложнее, но является общей. Часто требования предъявляются по разным причинам, но здесь вы все равно можете использовать одно и то же решение, и это будет оператор ObserveLatestOn
. Это вышло из банков, где нам нужно показывать только самую последнюю цену. Если в то время, когда потребовалось сделать цену, многие другие цены были получены, мы должны показать только последнюю.
Вы можете увидеть, как это обсуждалось на форумах MSDN Rx, в блоге JamesWorld и видео на YouTube, в котором обсуждалось, как это происходило.
Вы просто обновите свой запрос, чтобы иметь новый оператор и передать его в соответствующий планировщик.
//TODO: Rename syncMessageObserver. It is not an Observer, it is an Observable.
Observable.Merge(
syncMessageObserver.Select(_=>"from message"),
Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(60000)).Timestamp().Select(_=>"from timer")
)
.ObserveLatestOn(Scheduler.CurrentThread)
.Subscribe(msg =>
{
// actual syncing stuff
});
Для получения дополнительной информации о том, что такое Планировщик и как выбрать подходящий для вас сценарий, см. Здесь. Если тестирование важно для вас, то вам также нужно будет найти здесь контент о том, как быстро и детерминировать модульное тестирование запланированного/параллельного кода.