简体   繁体   中英

Background work in WCF Rest Service

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?

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.

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM