0

In my application I have a server which provides a REST-Api where my UI can communicate with.

Now I have to start a long running Process on the Server but I want the client not to wait for the response of the server.

I know I could just fire and forget the Post-Call and not await the response but I need to know at the client that the Process on the server was startet correctly.

So I thought about the following:

[HttpPost]
[Route("startscan")]
public HttpResponseMessage StartScan()
{
  Task.Factory.StartNew( () =>
  { 
    //Do long running things here 
  }); 
  return Request.CreateResponse(HttpStatusCode.OK);
}

So my question now is: Will the task I started be executed to it's end? Background of the question is, that as far as I knwo a controller-instance is created for each call to it. So will the instance of the controller be terminated when the requested finished or will the Task I started run to it's end. The task can take up to 10 minutes or longer sometimes.

Tomtom
  • 9,087
  • 7
  • 52
  • 95
  • For every request you only get one response when the response finishes. You need two requests/response. First request will start process. Second request will return results of response. – jdweng Feb 01 '22 at 14:56
  • I don't need the response of this request. Therefor I have another way. I just want to finish the first request and let the task run – Tomtom Feb 01 '22 at 14:58
  • https://stackoverflow.com/questions/53183370/c-sharp-how-to-start-an-async-method-without-await-its-complete – spyros__ Feb 01 '22 at 15:05
  • Start Process on server using ASYNC method than send response to client. – jdweng Feb 01 '22 at 15:07
  • For the client it is enough to get the StatusCode 200 as soon as the process started on the server. I just want to know if the Task I startet in the StartScan-Methode will be executed until it's finished also the request is already done – Tomtom Feb 01 '22 at 15:09
  • 1
    Well, if your controller have any dependency that's used to carry over your task; when the Controller is disposed that dependency which is running your task wouldn't be alive so possibly your job didn't finish. – J.Salas Feb 01 '22 at 15:10
  • 2
    So (sorry for two lines) you need to keep the dependency alive in a new singleton service – J.Salas Feb 01 '22 at 15:11
  • Ok. And how to I keep it alive in a singleton-service? Delegate the Task in a static-class or so? – Tomtom Feb 01 '22 at 15:17
  • Web servers are not great for long running tasks. For example, IIS used to reset services after 28 hours, which could mean your long running task would be terminated. These days it would be better for your API to queue a message which a worker service will pick up and process. – Neil Feb 01 '22 at 15:20
  • Unfortunately I have to do it on the IIS and can not delegate it to another service. Like I said the runtime of the Task may be up to 10 Minutes but not much more – Tomtom Feb 01 '22 at 15:30

2 Answers2

0

A simple approach would be to just use an asynchronous method without awaiting the Task result like so:

[HttpPost]
[Route("startscan")]
public async HttpResponseMessage StartScan()
{
  DoLongRunningThings();
  return Request.CreateResponse(HttpStatusCode.OK);
}

public async Task DoLongRunningThings()
{
  // Do Stuff here
}

However, if you Processing is more complex and requires more resilience you should look into how to use background jobs. Here is a good collection of what you can use: https://stackoverflow.com/a/36098218/16154479

René
  • 100
  • 1
  • 8
0

Will the task I started be executed to it's end?

Probably yes, but also possibly no. Sometimes it won't be executed completely. This is the result of misusing an ASP.NET app (which handles HTTP requests) as a background service (which runs outside of a request context).

There is a best practice that avoids possibly-partial execution: a distributed architecture (as I describe on my blog). The idea is that your controller enqueues a message describing the work to be done into a durable queue and then returns. Then there's a separate background service that reads from the queue and does the actual work.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810