Should I use async/await in Hangfire job ? - asynchronous

I recently started using Hangfire to handle my background jobs in an ASP.NET project.
My jobs are involving lots, lots (and lots) of HTTP calls using WebRequest (I may migrate to something else, but that's for later).
While browsing SO on this subject, I stumbled upon people who do async calls in hangfire.
Is there any point in using async/await tasks inside a Hangfire job ? I'm aware that it is a queue, so jobs won't execute concurrently, but since my project has no GUI, is there any reason I would use async/await to do my HTTP calls inside a Hangfire job ?
PS : The requests that are involving a long-running job use the Task "design pattern", so clients won't experience any timeout

You can absolutely use Hangfire to run async methods, and use awaits within those async methods.
The SO question you linked to was making a blocking Wait call on the method passed to Hangfire to be serialized and then later executed by the hangfire service.
This is very different from something like
hangfireClient.Enqueue(() => myClass.RunAsync());
where RunAsync is an async method that contains awaits.
public async Task<bool> RunAsync() {
//do your work
var subJob = new worker();
return await subJob.DoWork();
}

Related

Task.run takes two threads in an asp .net request?

Service layer
public async Task<string> getAllAsync()
{
return await WCFMethodAsync();
}
Presentation layer
public class Customer : Controller
{
public async Task<string> Index()
{
var r = await Task.Run(getAllAsync());
return r;
}
}
I will describe what I think is happening. I would like to know if I am wrong.
the request takes a thread from ThreadPool
await returns an incomplete Task
Task.Run queues a Task to run getAllAsync
3.1. that will take a thread from the ThreadPool.
when the getAllAsync method finishes the taken thread returns to the group of threads
when the service method call end .net is notified and a thread is taken from the group of threads o terminate the request.
Where is the incomplete homework returned to? Since the method was executed inside Task.Run.
I would like to know the flow of the whole process.
Since a thread was initially taken from the thread group and task.run takes a work thread, the question is when the task ends the job (wcf) and a thread is taken to finish the request. How many threads were used to process the request?
Your getAllAsync method is a I/O bound operation, because you are making a network call to reach your WCF service instance.
That means the getAllAsync will be executed by the network driver. It is an asynchronous non-blocking promise task. The calling thread is not blocked until the asynchronous I/O operation finishes. When it finishes the ThreadPool will be notified about it.
On the other hand the Task.Run is design for CPU bound operation.
The Task.Run returns a delegate task and it is used to queue a work on the ThreadPool. That work will be processed by one of the CPU core.
So if you put an asynchronous I/O work (kick-off) call on a dedicated Thread then that is just wasting valuable resources.

Can Hangfire Work as A Simple Method Timer?

I have a .NET Core Web API application. The app contains models for db access and a way to send emails to users. My end goal is to call a method nightly (to email users that their registration expired and to mark it expired in the database).
So, in short, I can build an endpoint and call it manually every night. Or build a windows service to call the endpoint. Or build a windows service to do the work. But I want to keep the logic in one application.
My ideal solution would be to have a timer running inside my app and calling a method in a service every 24 hours. Of course, that's not possible, so I am looking at Hangfire. The official documentation seems to indicate that there is a lot of overhead.
Hangfire keeps background jobs and other information that relates to the processing inside a persistent storage. Persistence helps background jobs to survive on application restarts, server reboots, etc.
Do I need this if I just want to call a method?
Background jobs are processed by Hangfire Server. It is implemented as a set of dedicated (not thread pool’s) background threads that fetch jobs from a storage and process them. Server is also responsible to keep the storage clean and remove old data automatically.
Do I even need jobs?
Is there a way to JUST call a method without all this overhead with Hangfire?
tl;dr: Are there options to opt out of the dashboard, database connectivity, etc and just have Hangfire work as a timer?
My ideal solution would be to have a timer running inside my app and calling a method in a service every 24 hours. Of course, that's not possible...
It's very possible, actually, using IHostedService. You should take some time to read the full documentation, but simply, for your scenario, you'd just need something like:
internal class NightlyEmailHostedService : IHostedService, IDisposable
{
private Timer _timer;
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromHours(24));
return Task.CompletedTask;
}
private void DoWork(object state)
{
// send email
}
public Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
Then, in Startup.cs just add:
services.AddHostedService<NightlyEmailHostedService>();
Now, that's an extremely naive approach. It basically just kicks off a timer that will run once every 24 hours, but depending on when your app started, it may not always be at night. In reality, you'd likely want to have the timer run every minute or so, and check against a particular time you actually want the email to go out. There's an interesting implementation of handling cron-style times via an IHostedService you might want to reference.
The long and short is that it's very possible to do this all in your app, without requiring anything additional like Hangfire. However, you have to a do a bit more work than you would have to using something like Hangfire, of course.

Can I use async / await in an asp.net hosted RESTful API?

Is it possible to have have asynchronous calls to a RESTful API hosted under asp.net?
I have a long running process. I want to trigger it to start via an http GET request and then check on its progress periodically. How do I do this using the new C#5 async / await syntax?
I have a detailed example in this question:
How do I call an asynchronous process from an asp.net hosted module using C#5 async / await?
I think you don't need to use await or async. Maybe you can start a new thread to run the long time task, and return a task id to the client immediately. And the client use this id to check the progress of the task.

Using Task or async/await in IHttpAsyncHandler

Since the very begining of writing ASP.NET applications when I wanted to add a threading there are 3 simple ways I can accomplish threading within my ASP.NET application :
Using the System.Threading.ThreadPool.
Using a custom delegate and calling its BeginInvoke method.
Using custom threads with the aid of System.Threading.Thread class.
The first two methods offer a quick way to fire off worker threads for your application. But unfortunately, they hurt the overall performance of your application since they consume threads from the same pool used by ASP.NET to handle HTTP requests.
Then I wanted to use a new Task or async/await to write IHttpAsyncHandler. One example you can find is what Drew Marsh explains here : https://stackoverflow.com/a/6389323/261950
My guess is that using Task or async/await still consume the thread from the ASP.NET thread pool and I don't want for the obvious reason.
Could you please tell me if I can use Task (async/await) on the background thread like with System.Threading.Thread class and not from thread pool ?
Thanks in advance for your help.
Thomas
This situation is where Task, async, and await really shine. Here's the same example, refactored to take full advantage of async (it also uses some helper classes from my AsyncEx library to clean up the mapping code):
// First, a base class that takes care of the Task -> IAsyncResult mapping.
// In .NET 4.5, you would use HttpTaskAsyncHandler instead.
public abstract class HttpAsyncHandlerBase : IHttpAsyncHandler
{
public abstract Task ProcessRequestAsync(HttpContext context);
IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
var task = ProcessRequestAsync(context);
return Nito.AsyncEx.AsyncFactory.ToBegin(task, cb, extraData);
}
void EndProcessRequest(IAsyncResult result)
{
Nito.AsyncEx.AsyncFactory.ToEnd(result);
}
void ProcessRequest(HttpContext context)
{
EndProcessRequest(BeginProcessRequest(context, null, null));
}
public virtual bool IsReusable
{
get { return true; }
}
}
// Now, our (async) Task implementation
public class MyAsyncHandler : HttpAsyncHandlerBase
{
public override async Task ProcessRequestAsync(HttpContext context)
{
using (var webClient = new WebClient())
{
var data = await webClient.DownloadDataTaskAsync("http://my resource");
context.Response.ContentType = "text/xml";
context.Response.OutputStream.Write(data, 0, data.Length);
}
}
}
(As noted in the code, .NET 4.5 has a HttpTaskAsyncHandler which is similar to our HttpAsyncHandlerBase above).
The really cool thing about async is that it doesn't take any threads while doing the background operation:
An ASP.NET request thread kicks off the request, and it starts downloading using the WebClient.
While the download is going, the await actually returns out of the async method, leaving the request thread. That request thread is returned back to the thread pool - leaving 0 (zero) threads servicing this request.
When the download completes, the async method is resumed on a request thread. That request thread is briefly used just to write the actual response.
This is the optimal threading solution (since a request thread is required to write the response).
The original example also uses threads optimally - as far as the threading goes, it's the same as the async-based code. But IMO the async code is easier to read.
If you want to know more about async, I have an intro post on my blog.
I've been looking for information through internet for a couple of days. Let me sum up what I found until now :
ASP.NET ThreadPool facts
As Andres said: When async/await will not consume an additional ThreadPool thread ? Only in the case you are using BCL Async methods. that uses an IOCP thread to execute the IO bound operation.
Andres continues with ...If you are trying to async execute some sync code or your own library code, that code will probably use an additional ThreadPool thread unless you explicitely use the IOCP ThreadPool or your own ThreadPool.
But as far as I know you can't chose whetever you want to use a IOCP thread, and making correct implementation of the threadPool is not worth the effort. I doubt someone does a better one that already exists.
ASP.NET uses threads from a common language runtime (CLR) thread pool to process requests. As long as there are threads available in the thread pool, ASP.NET has no trouble dispatching incoming requests.
Async delegates use the threads from ThreadPool.
When you should start thinking about implementing asynchronous execution ?
When your application performs relatively lengthy I/O operations (database queries, Web service calls, and other I/O operations)
If you want to do I/O work, then you should be using an I/O thread (I/O Completion Port) and specifically you should be using the async callbacks supported by whatever library class you're using. Theirs names start with the words Begin and End.
If requests are computationally cheap to process, then parallelism is probably an unnecessary overhead.
If the incoming request rate is high, then adding more parallelism will likely yield few benefits and could actually decrease performance, since the incoming rate of work may be high enough to keep the CPUs busy.
Should I create new Threads ?
Avoid creating new threads like you would avoid the plague.
If you are actually queuing enough work items to prevent ASP.NET from processing further requests, then you should be starving the thread pool! If you are running literally hundreds of CPU-intensive operations at the same time, what good would it do to have another worker thread to serve an ASP.NET request, when the machine is already overloaded.
And the TPL ?
TPL can adapt to use available resources within a process. If the server is already loaded, the TPL can use as little as one worker and make forward progress. If the server is mostly free, they can grow to use as many workers as the ThreadPool can spare.
Tasks use threadpool threads to execute.
References
http://msdn.microsoft.com/en-us/magazine/cc163463.aspx
http://blogs.msdn.com/b/pfxteam/archive/2010/02/08/9960003.aspx
https://stackoverflow.com/a/2642789/261950
Saying that "0 (zero) threads will be servicing this request" is not accurate entirely.
I think you mean "from the ASP.NET ThreadPool", and in the general case that will be correct.
When async/await will not consume an additional ThreadPool thread?
Only in the case you are using BCL Async methods (like the ones provided by WebClient async extensions) that uses an IOCP thread to execute the IO bound operation.
If you are trying to async execute some sync code or your own library code, that code will probably use an additional ThreadPool thread unless you explicitely use the IOCP ThreadPool or your own ThreadPool.
Thanks,
Andrés.
The Parallel Extensions team has a blog post on using TPL with ASP.NET that explains how TPL and PLINQ use the ASP.NET ThreadPool. The post even has a decision chart to help you pick the right approach.
In short, PLINQ uses one worker thread per core from the threadpool for the entire execution of the query, which can lead to problems if you have high traffic.
The Task and Parallel methods on the other hand will adapt to the process's resources and can use as little as one thread for processing.
As far as the Async CTP is concerned, there is little conceptual difference between the async/await construct and using Tasks directly. The compiler uses some magic to convert awaits to Tasks and Continuations behind the scenes. The big difference is that your code is much MUCH cleaner and easier to debug.
Another thing to consider is that async/await and TPL (Task) are not the same thing.
Please read this excellent post http://blogs.msdn.com/b/ericlippert/archive/2010/11/04/asynchrony-in-c-5-0-part-four-it-s-not-magic.aspx to understand why async/await doesn't mean "using a background thread".
Going back to our topic here, in your particular case where you want to perform some expensive calculations inside an AsyncHandler you have three choices:
1) leave the code inside the Asynchandler so the expensive calculation will use the current thread from the ThreadPool.
2) run the expensive calculation code in another ThreadPool thread by using Task.Run or a Delegate
3) Run the expensive calculation code in another thread from your custom thread pool (or IOCP threadPool).
The second case MIGHT be enough for you depending on how long your "calculation" process run and how much load you have. The safe option is #3 but a lot more expensive in coding/testing. I also recommend always using .NET 4 for production systems using async design because there are some hard limits in .NET 3.5.
There's a nice implementation of HttpTaskAsyncHandler for the .NET 4.0 in the SignalR project. You may want to ckeck it out: http://bit.ly/Jfy2s9

ASP.NET Web Service call in another Thread

We are making a web service call on some data updates to sync another database. This web service call takes up some response time. Would adding it in a thread help at all? Any downfalls of doing this? If the web service calls fails, it fails and that is it. It is like a fire and forget call.
You could use an Asynchronous Web Service call using asyncronous callbacks to prevent blocking of your main thread.
By making an asynchronous call to a Web service, you can continue to
use the calling thread while you wait for the Web service to respond.
This means users can continue to interact with your application
without it locking up while the Web service access proceeds.
From MSDN: Making Asynchronous Web Service Calls
If it's taking long enough to hang the user interface then calling it on another thread is the recommended thing to do.
In addition to Tudor's answer I would suggest that you start off by using the new Task class from .NET 4.0.from task parallel library. Example would be:
Task backgroundProcess = new Task(() =>
{
service.CallMethod();
});
I strongly advice against using Async Web Service calls (including making calls in separate threads) from a web app. Instead use alternate approach like Ajax, and make this webservice call from an Ajax Call instance. There is no easy approach in the web context to handle threading and Async calls.

Resources