Reputation: 51
Here we have a requirement that in the ASP.NET Core Web API controller, a job should be created and executed in the background, and the controller should reply the response immediately once the job starts running. There will be another controller API which could query the execution status of the job but that is a different topic.
To be simpler, the code is similar to the following:
public class Job
{
public async Task RunAsync()
{
//...
}
}
// API Controller code
private Job _job;
[HttpPost]
public async Task<IActionResult> CreateJob()
{
_job.RunAsync(); // <-- No awaiting, making the job running in the background
await DoAnotherThingAsync();
return Ok();
}
I found that sometimes the running of this background job will be interrupted for some reasons - After this CreateJob
API has returned, it looks like the _job.RunAsync()
will not always completely finish its work - its execution thread could be killed at any time.
I know this is not a good implementation, but there are some questions:
await
before _job.RunAsync()
, this CreateJob
API will eventually wait the background job to complete before it returns to the caller, which makes the job execution to be synchronous, right?Upvotes: 0
Views: 1848
Reputation: 456457
I found that sometimes the running of this background job will be interrupted for some reasons - After this CreateJob API has returned, it looks like the _job.RunAsync() will not always completely finish its work - its execution thread could be killed at any time.
Yup.
Why could this background job execution be interrupted?
Any number of reasons! I explain several of them in my blog post (see the section "Shutdowns Are Normal"):
In-memory work cannot survive application shutdown (and shutdowns are normal), so the only proper (reliable) solution is to store them somewhere durable (i.e., not in memory).
If I append await before _job.RunAsync(), this CreateJob API will eventually wait the background job to complete before it returns to the caller, which makes the job execution to be synchronous, right?
Well, that depends on what you mean by "synchronous".
I would say that no, it's still asynchronous. With the await
, the request thread is not blocked, so it's asynchronous.
But: ASP.NET will (asynchronously) wait until the job completes before returning the HTTP response.
Since ASP.NET doesn't return the HTTP response until the job is completed, then at a higher conceptual level you could say it was "synchronous".
Except adopting third party frameworks like Quartz.NET and Hangfire, is there any simple solution to this issue?
No.
I have a blog series on this subject explaining why it's complex. Hangfire is about as simple of a solution as you're going to get.
Upvotes: 2
Reputation: 10463
The first job interrupted because the method doesn't monitor it. The method returns exactly when second job finishes regardless the state of the first. You have to use synchronisation to ensure both jobs finished before leaving the method
var task1 = DoWorkAsync();
var task2 = DoMoreWorkAsync();
await Task.WhenAll(task1, task2);
Upvotes: 0