2

I have a WCF Rest service that exposes a web method which should start off a long running process and then immediately return an id representing the task that can be used to track the status of the task.

[WebGet]
public Task<Guid> LongRunningProcess()
{
    var taskId = new Guid();

    var task = Task.Factory.StartNew(() =>
    {
        //Perform long running task
    }

    task.ContinueWith(task =>
    {
        //Send a notification to the client that the task has completed.
    }

    return taskId;
}

My question is that, is this the correct way to do it? or is there a better and more lightweight approach?

Randyka Yudhistira
  • 3,612
  • 1
  • 26
  • 41
There is no spoon
  • 1,775
  • 2
  • 22
  • 53

2 Answers2

0

What you sketched up there is (with minor correction) a way to achieve what you want to do. The harder part is the notification of clients (we do so using SignalR hubs successfully, but the exact mechanism is up to you).

The minor correction I spoke about is that the return type of your method should be just Guid in your code above.

Some notes: Performance-wise the TPL scales pretty well (IMO) but on a lager scale you may want to be able to distribute that long-running tasks over multiple servers etc...

For this case I'll recommend you to have a look at distributes job queues (Resque for example, .NET ports exist) which are perfect for this kind of use cases.

pysco68
  • 1,136
  • 9
  • 15
0

My understanding is that if your work is CPU bound, you are better off executing the work synchronously. With your approach the request will get parked and the original request thread will get freed up, but then are handing off the work to another thread, and the request doesn't complete until that thread is finished. You might as well do the work in the original thread.

If you had some IO in there it would make sense to make that asynchronous as asynchronous IO does not use a thread and it would free up your request thread to handle other requests, which improves your scalability.

UPDATE

I think the approach you are taking is good, but given that you are using .NET 4.5 I'd use async-await as it results in simpler code. I would then use the asynchronous API of IO operations and await its result. Eg:

[WebGet]
public async Task<Guid> LongRunningProcess()
{
    var taskId = new Guid();

    // IO bound operation
    var dbResult = await readFromDbAsync();

    // IO bound operation
    var dbResult = await readFromDbAsync();

    // CPU bound?
    generateReport(dbResult);

    // IO bound operation
    await sendNotification();

    return taskId;
}

If you are not familiar with async-await, I have written an intro to it here.

NeddySpaghetti
  • 13,187
  • 5
  • 32
  • 61
  • Thanks for that. The operation reads from a database and produces a report which is saved to disk. Once the client has been notified that the report is ready then they can make another call to retrieve the report. In this situation would the above code serve this purpose? I was many clients to be able to call this method and start off the production of one or more reports. In other words a client may call this method several times, once per report they wish to view, and you may have many clients doing this. – There is no spoon Feb 28 '15 at 03:36
  • Later I want to add queuing of requests but I'll get to that later, right now I'm trying to understand how to simply produce each report in the background so that the service can serve many requests and produce reports in parallel. – There is no spoon Feb 28 '15 at 03:37
  • Thanks for your answer and code sample. What I'm actually looking to achieve is for the service method to kick off a long running process (that access the database, builds a report and saves the report to disk) and immediately return an Id, which I have namied taskId, that the user can use to track the status of the report and later be notified that it is ready for viewing. Won't having the await in the method mean that the service method won't return until the report has completed rather than returning immediately with the task id? thanks again. – There is no spoon Mar 01 '15 at 05:41
  • That's correct, doing this with `async` is may not be the best approach. See this question http://stackoverflow.com/a/19918929/1239433. – NeddySpaghetti Mar 01 '15 at 06:09