Rx observable which publishes a value if certain timeout expires

瘦欲@ 提交于 2019-12-09 00:57:23

问题


I have a method that returns an observable. This observable should (if evetything is working right) publish a value each second. What I would like to do is have it publish some custom alert value if a certain time has passed with no output.

private IObservable<string> GetStatus()
{
    return statusProvider
                .Subscribe(statusKey)  //returns an IObservable<string>
                .Select(st => st.ToUpper())
                .DistinctUntilChanged()
                .TakeUntil(disposed)
                .Replay(1)
                .RefCount();
}

Is there a simple way for me to modify the above so that if no status update has come in for 30 seconds, the statusProvider publishes "bad" and then if an update does come in after that, it get published as usual and the timer is restarted to 30 secs again?


回答1:


Here is a way. Starts a timer which will yield "bad" when it expires. Each time your statusProvider produces a status, the timer gets reset.

var statusSignal = statusProvider
            .Subscribe(statusKey)  //returns an IObservable<string>
            .Select(st => st.ToUpper())
            .Publish()
            .RefCount();

// An observable that produces "bad" after a delay and then "hangs indefinately" after that
var badTimer = Observable
    .Return("bad")
    .Delay(TimeSpan.FromSeconds(30))
    .Concat(Observable.Never<string>());

// A repeating badTimer that resets the timer whenever a good signal arrives.
// The "indefinite hang" in badTimer prevents this from restarting the timer as soon
// as it produces a "bad".  Which prevents you from getting a string of "bad" messages
// if the statusProvider is silent for many minutes.
var badSignal = badTimer.TakeUntil(statusSignal).Repeat();

// listen to both good and bad signals.
return Observable
    .Merge(statusSignal, badSignal)
    .DistinctUntilChanged()
    .Replay(1)
    .RefCount();



回答2:


I think that the following should work. It uses Throttle which will wait until 30 seconds have passed with no input before sending anything. You can then merge this with your preexisting source to get your desired behaviour.

var bad = source
    .Throttle(TimeSpan.FromSeconds(30))
    .Select(_ => "bad");

var merged = source.Merge(bad);


来源:https://stackoverflow.com/questions/23394441/rx-observable-which-publishes-a-value-if-certain-timeout-expires

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!