Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run async method regularly with specified interval

I need to publish some data to the service from the C# web application. The data itself is collected when user uses the application (a kind of usage statistics). I don't want to send data to the service during each user's request, I would rather collect the data in the app and send then all the data in a single request in a separate thread, that does not serve the users requests (I mean user does not have to wait for the request to be processed by the service). For this purpose I need a kind of JS's setInterval analog - the launch of the function each X seconds to flush all collected data to the service.

I found out that Timer class provides somewhat similar (Elapsed event). However, this allows to run the method only once, but that's not a big issue. The main difficulty with it is that it requires the signature

void MethodName(object e, ElapsedEventArgs args) 

while I would like to launch the async method, that will call the web-service (input parameters are not important):

async Task MethodName(object e, ElapsedEventArgs args) 

Could anyone advise how to solve the described task? Any tips appreciated.

like image 423
Eadel Avatar asked May 26 '15 14:05

Eadel


People also ask

Should you always await async methods?

If a method is declared async, make sure there is an await! If your code does not have an await in its body, the compiler will generate a warning but the state machine will be created nevertheless, adding unnecessary overhead for an operation that will actually never yield.

What happens when you call async method without await?

The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.

Does await run synchronously?

The await operator suspends the evaluation of the enclosing async method until the asynchronous operation completes. When the asynchronous operation finishes, the await operator returns the result of the operation, if any. If the async method does not contain an await operator, the method executes synchronously.


2 Answers

The async equivalent is a while loop with Task.Delay (which internally uses a System.Threading.Timer):

public async Task PeriodicFooAsync(TimeSpan interval, CancellationToken cancellationToken) {     while (true)     {         await FooAsync();         await Task.Delay(interval, cancellationToken)     } } 

It's important to pass a CancellationToken so you can stop that operation when you want (e.g. when you shut down your application).

Now, while this is relevant for .Net in general, in ASP.Net it's dangerous to do any kind of fire and forget. There are several solution for this (like HangFire), some are documented in Fire and Forget on ASP.NET by Stephen Cleary others in How to run Background Tasks in ASP.NET by Scott Hanselman

like image 185
i3arnon Avatar answered Oct 13 '22 13:10

i3arnon


The simple way of doing this is using Tasks and a simple loop:

public async Task StartTimer(CancellationToken cancellationToken) {     await Task.Run(async () =>    {       while (true)       {           DoSomething();           await Task.Delay(10000, cancellationToken);           if (cancellationToken.IsCancellationRequested)               break;       }    });  } 

When you want to stop the thread just abort the token:

cancellationToken.Cancel(); 
like image 31
Guy Levin Avatar answered Oct 13 '22 15:10

Guy Levin