title: How do I create an Observable Timer that calls a method and blocks on cancellation if the method is running until it finishes?
body: <p>My requirements:</p>
  
  <ol>
  <li>Run method DoWork on a specified interval.</li>
  <li>If stop is called between calls to DoWork just stop the timer.</li>
  <li>If stop is called while DoWork is running, block until DoWork is finished.</li>
  <li>If DoWork takes too long to finish after stop is called, timeout.</li>
  </ol>
  
  <p>I have a solution that seems to work so far, but I'm not super happy with it and think I may be missing something. The following is the void Main from my test app:</p>
  
  <pre><code>var source = new CancellationTokenSource();
  
  // Create an observable sequence for the Cancel event.
  var cancelObservable = Observable.Create&lt;Int64&gt;(o =&gt;
  {
      source.Token.Register(() =&gt;
      {
          Console.WriteLine("Start on canceled handler.");
          o.OnNext(1);
          Console.WriteLine("End on canceled handler.");
      });
  
      return Disposable.Empty;
  });
  
  var observable =
      // Create observable timer.
      Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(10), Scheduler.Default)
          // Merge with the cancel observable so we have a composite that 
          // generates an event every 10 seconds AND immediately when a cancel is requested.
          .Merge(cancelObservable)
          // This is what I ended up doing instead of disposing the timer so that I could wait
          // for the sequence to finish, including DoWork.
          .TakeWhile(i =&gt; !source.IsCancellationRequested)
          // I could put this in an observer, but this way exceptions could be caught and handled
          // or the results of the work could be fed to a subscriber.
          .Do(l =&gt;
          {
              Console.WriteLine("Start DoWork.");
              Thread.Sleep(TimeSpan.FromSeconds(5));
              Console.WriteLine("Finish DoWork.");
          });
  
  var published = observable.Publish();
  
  var disposable = published.Connect();
  
  // Press key between Start DoWork and Finish DoWork to test the cancellation while
  // running DoWork.
  // Press key between Finish DoWork and Start DoWork to test cancellation between
  // events.
  Console.ReadKey();
  
  // I doubt this is good practice, but I was finding that o.OnNext was blocking
  // inside of register, and the timeout wouldn't work if I blocked here before
  // I set it up.
  Task.Factory.StartNew(source.Cancel);
  
  // Is there a preferred way to block until a sequence is finished? My experience
  // is there's a timing issue if Cancel finishes fast enough the sequence may already
  // be finished by the time I get here and .Wait() complains that the sequence contains
  // no elements.
  published.Timeout(TimeSpan.FromSeconds(1))
      .ForEach(i =&gt; { });
  
  disposable.Dispose();
  
  Console.WriteLine("All finished! Press any key to continue.");
  Console.ReadKey();
  </code></pre>