Home > Mobile >  What happens when a Task is run but finishes after the HTTP response is returned?
What happens when a Task is run but finishes after the HTTP response is returned?

Time:09-29

I found this (simplified) action method in an ASP.NET project:

    [Route("")]
    public async Task<HttpResponseMessage> Get()
    {  
        // other await calls here...
        StartReportGenerationInBackground();
        return CreateReportRedirectResponse();
    }

    private void StartReportGenerationInBackground()
    {
        // GENERATE Report in background worker
        new Task(async () => // concern with this new thread is that IIS could kill the process given the response will have already been returned.
        {
            var fileResult = await GetReportBytesAsync();
        }).Start();
    }
    
    private async Task<FileResult> GetReportBytesAsync()
    {
        return await Task.Run(() => GetReportBytes());
    }
    
    private FileResult GetReportBytes()
    {
        // lots of CPU bound work here
    }
    
    private HttpResponseMessage CreateReportRedirectResponse()
    {
        var redirectResponse = Request.CreateResponse(HttpStatusCode.Moved);
        redirectResponse.Headers.Location = new Uri("<reportLocationHere>");
        return redirectResponse;
    }

I assume the call to StartReportGenerationInBackground() returns immediately, and the response is returned to the client.

What happens to the thread that was kicked off to run the GetReportBytes()?

Does it still run in the background even though the response was already sent back to the client?

CodePudding user response:

new Task(...).Start(); is an unnecessarily complex way of saying _ = Task.Run(...);

I assume the call to StartReportGenerationInBackground() returns immediately, and the response is returned to the client.

Yes. This is a form of "fire and forget", an attempt at a solution for returning early from HTTP requests.

What happens to the thread that was kicked off to run the GetReportBytes()?

Does it still run in the background even though the response was already sent back to the client?

// concern with this new thread is that IIS could kill the process given the response will have already been returned.

Well, that's the tricky part. The code will continue running in the background. Until it doesn't.

There's nothing in ASP.NET (or IIS) that will kill this code as soon as the response returns, so the code is allowed to continue running. But at the same time, there's nothing in ASP.NET (or IIS) that will keep it running until it finishes.

More specifically, this application doesn't allow shutdowns. If the application is ever stopped, this kind of background work is discarded (without even a log message to inform you it happened). Stopping happens regularly: when deploying a new version, when scaling down, when rebooting after patch night, when IIS decides to restart periodically... And those are just the graceful restarts; there's also the rude restarts, such as hardware failures, bluescreens, and top-level app exceptions.

The bottom line is that if this app is restarted for any reason, all background work like this will be lost. For that reason, I would say this code is dangerous and should not be used.

There are proper solutions that do allow returning early from HTTP requests, most notably the basic distributed architecture that I describe on my blog.

  • Related