Sleep-defiant timer, ideally Reactive
Asked Answered
V

0

8

The following code ticks nicely every two minutes under normal conditions:

Observable.Interval(TimeSpan.FromSeconds(120)).Subscribe(
    l =>
        {                        
            var now = DateTime.Now;
            Console.WriteLine(
                "Tick at " + now.ToString("hh:mm:ss") + " Count " + l.ToString());        
        });

Behavior after device sleeps for some time and then resumes

Tick at 11:30:00 Count 0
(11:31:55 put computer to sleep)
(no tick at 11:32:00 because PC is suspended, which is fine)
(no tick at 11:34:00 because PC is suspended)
(11:34:30 wake computer up)
(no tick as soon as possible to indicate that ticks were missed) 
Tick at 11:36:30 Count 1

It seems that the Observable Interval timer kind of resets itself and starts the interval anew from the time the device resumes. (I observed similar behavior with Observable Timer)

Sleep-aware timer

I need a timer that does not restart the interval on resume, but ticks once if any ticks missed during sleep

  • not once for each tick missed, but once in total if any number of ticks missed
  • this is especially relevant for TimeSpans of hours or days, which in some cases will make the timer never tick again if a laptop goes to sleep even once a day
  • would be great to have an overload for Observable Interval and Timer that specifies such misfire instructions?
  • if cannot make it work in the Rx Observable space, are there other timers out there are sleep-defiant in some configurable way?
  • haven't tested Quartz yet for this, but would ideally like to not have to include more dependencies, so an Observable or managed .NET solution is preferred
  • the same should work for other deeper sleep modes e.g. hibernation
Victory answered 20/10, 2015 at 11:19 Comment(5)
At these sort of time-scales, you really ought to be looking at scheduling (i.e. you've mentioned Quartz) rather than timing.Stelly
Just an idea: behavior of Observable.Interval during Sleep mode changes if you provide either NewThreadScheduler.Default or CurrentThreadScheduler.Instance. In this case the timer does not reset itself, but emits "slept" values once out of Sleep mode and continues with the "correct timing". Could it be possible to implement your own IScheduler that buffers values based on Sleep mode ? (you can detect these changes with Observable.FromEventPattern<PowerModeChangedEventHandler, PowerModeChangedEventArgs> )Jetton
@Jetton I tried Observable.Interval(TimeSpan.FromSeconds(120), NewThreadScheduler.Default) and it did emit "slept" values, but not as soon as possible on resume but after the set 2 minute interval after resume i.e. multiple slept values together were emitted but interval was still reset Then after that normal values continued from original timing start, but that's too late still. For instance, if I resumed at 11:34:30 the "slept" values would be signalled as late as 11:36:30 and the next normal value at 11:38:00 (because I originally subscribed at 11:30:00)Victory
@Cel, I'm not confident why it behaves like so :) not sure if my idea is valid or not. I still believe the answer should include Sleep mode detection with the PowerModeChanged event.Jetton
@Victory - One aspect here that makes sense to me is that Interval isn't the same as a Timer that repeats itself. It fires once, waits for all subscribers to finish, and then schedules the next firing, and the cycle repeats. So when your machine goes to sleep it doesn't fire so it doesn't reschedule, hence you're not ever going to get "missing ticks".Wahlstrom

© 2022 - 2024 — McMap. All rights reserved.