Reputation: 403
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
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
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
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
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