My goal is to have an update handler be called no more than once per 5 seconds for "Type2" objects. The observable will be generating more than one value per 5 seconds but I want to ignore all of them that occur within 5 seconds of the last handled update.
I asked this question here: Throttle only if specific condition met
and got good feedback. It led me to use Observable.Window to try to achieve my goal. I thought I had it working but it turns out that it can produce incorrect output if the first update comes right before a window closes (so the update is handled) and then once the next window opens, another update arrives and is also handled, when I don't want it to since it came within 5 seconds of the last handled update.
Here is some code to demonstrate the issue, slightly modified from the code in the link:
var source = new Subject<Thing>();
var feed = source.Publish().RefCount();
var ofType1 = feed.Where(t => t.ActivationType == "Type1");
var ofType2 = feed
.Where(t => t.ActivationType == "Type2")
.Window(() =>
Observable.Timer(TimeSpan.FromSeconds(5))
.Do(t => Console.WriteLine("\nTICK: " + DateTime.Now.ToString("hh:mm:ss:fff"))))
.Select(x => x.Take(1))
.Merge()
.Do(t => Console.WriteLine("A new window opened " + DateTime.Now.ToString("hh:mm:ss:fff")));
var query = ofType1.Merge(ofType2);
query.Subscribe(t => Console.WriteLine("UPDATE: " + t.ID + " " + DateTime.Now.ToString("hh:mm:ss:fff")));
int msDelay = 3000;
Task task = Task.Factory
.StartNew(() => { Thread.Sleep(msDelay); })
.ContinueWith((Task starter) =>
{
while (running)
{
var thing = new Thing(); //Note that all Things are by default Type2
source.OnNext(thing);
Thread.Sleep(100);
}
}, TaskContinuationOptions.LongRunning);
Console.ReadLine();
So, the subscription is made and once the subscription is made, the Observable.Timer used in the Window begins. The while loop that is used to produce values does not begin until after a 3000 ms delay.
The output looks like:
A new window opened 03:48:03:725
UPDATE: 1ac54fb3-f73d-4840-b4d8-95d4250ce65d 03:48:03:752
TICK: 03:48:05:714
A new window opened 03:48:05:754
UPDATE: 12d36e53-010f-4ccd-b9f8-2951b085f88c 03:48:05:754
TICK: 03:48:10:730
A new window opened 03:48:10:755
UPDATE: 25d84e72-94f9-4f50-83f4-14c1004c10fa 03:48:10:755
TICK: 03:48:15:738
A new window opened 03:48:15:755
UPDATE: 5f32b7d5-196f-445c-bf25-5c362b2fd6f0 03:48:15:755
TICK: 03:48:20:747
A new window opened 03:48:20:756
UPDATE: e3a3a30d-8031-41b5-b115-499dbe91aaf7 03:48:20:756
TICK: 03:48:25:755
A new window opened 03:48:25:756
UPDATE: 239fb25b-5135-463b-bf7e-5728ffa07f5c 03:48:25:756
As you can see, the first Type2 update comes in while a window is open, so it gets handled. Then, 2 secs later, the Window's timer ticks and a new window is opened. It immediately handles the next Type2 update, which I don't want it to do. After that it looks to work normally (one update every 5 secs as defined in the Window declaration).
Is there a way or another method I can use to make sure that only one update per 5 seconds (or whatever timeframe I choose) is ever handeld?