Ijas
Ijas

Reputation: 403

Calling a method in specific interval

I need to run a method in a specific interval. How can I achieve it through c#

I wrote a code but it is not repeating. It is executing only one time. can anyone explain to me what is observable and cancellation token. how to use it

IObservable<long> observable = Observable.Interval(TimeSpan.FromHours(1));
System.Threading.CancellationTokenSource source = new System.Threading.CancellationTokenSource();
observable.Subscribe(x =>
{
    System.Threading.Tasks.Task task = sampleMethod();
    task.Start();
}, source.Token);

Upvotes: 1

Views: 1672

Answers (4)

OlegI
OlegI

Reputation: 6010

You can achieve that in multiple ways. One of the easiest one would be something like this:

public async Task RunScheduleJob(CancellationToken token)
{
  while(!token.IsCancellationRequest)
  {
    YourMethod();
    await Task.Delay(TimeSpan.FromHours(1), token)
  }
}

PS. For such a simple job you don't need to use Reactive Extensions or any other external library. You can achieve it by just playing around with Task instances

Upvotes: 2

Enigmativity
Enigmativity

Reputation: 117064

Rx is an awesome way to handle this situation. It is super clean.

The most basic rewrite of your code in your question is this:

IObservable<Unit> observable =
    from i in Observable.Interval(TimeSpan.FromHours(1))
    from t in Observable.FromAsync(() => sampleMethod())
    select t;

IDisposable subscription = observable.Subscribe();

There's no need for a cancellation token as you simply need to call subscription.Dispose() to stop this subscription.

However, if your sampleMethod() call was long-running then calling subscription.Dispose() would stop the observable, but the task would run to completion. If you specifically wanted to stop the task too then the call to the task would need to take a cancellation token and use it to stop itself.

Yor calling code would then be this:

IObservable<Unit> observable =
    from i in Observable.Interval(TimeSpan.FromHours(1))
    from t in Observable.FromAsync(ct => sampleMethod(ct))
    select t;

The only difference is that the FromAsync call passes a CancellationToken to the sampleMethod call that will be cancelled when you call subscription.Dispose().

Upvotes: 1

Georg
Georg

Reputation: 5781

No need for Rx if you just need a timer functionality. You can just go with a Timer from System.Threading:

    var timer = new Timer(_ =>
    {
        // repeating code goes here
        // the argument is an optional state that you can pass into the constructor
    });
    timer.Change( dueTime: TimeSpan.FromSeconds(1), period: TimeSpan.FromSeconds(0.1));
    // run your app
    timer.Dispose();

The advantage of the Timer is that it allows you to reconfigure it anytime (if you want to Change the period, just call Change again), temporarily disable it and cleanly remove it (calling Dispose).

Upvotes: 0

Zazaeil
Zazaeil

Reputation: 4119

Observable.Interval(TimeSpan.FromHours(1)).SelectMany(_ => sampleMethod()).Subscribe(). Ignoring for the moment cancellation behavior (which is easy to add), you just take the Interval and rightly map it to an async routine represented as Task (internally treated as IObservable<>, btw there is .ToObservable() extension method to convert Task). Note that SelectMany(...) is fatefully important here: otherwise the Rx framework won't await for Task completion, won't capture possible exceptions and won't preserve the original order of events.

CancellationToken is used to unsubscribe from the Observable you made up. It is analogous to the IDisposable in that sense that both serve for the same goal: to stop and cleanup your subscription. Thus, once you call Cancel() on it, you won't get any update.

P.S. Are you sure that FromHours(1) is right? You may want less longer interval, for example FromMinutre(1).

Upvotes: 0

Related Questions