Cancel a long running task over WCF from client
Asked Answered
B

2

6

I have a WCF service set to PerCall

I would like to know how I can send a Start call from the client to start a long running process, and send a Cancel command to cancel it

My WCF service looks something like this

 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class Service1 : IService1
    {

        CancellationTokenSource cancelToken = new CancellationTokenSource();



        public void Start()
        {

            var compute = Task.Factory.StartNew(StartLongRunningTask, cancelToken.Token);
        }

        public void Stop()
        {

            cancelToken.Cancel();
        }

            private void StartLongRunningTask()
            {
                  //process here

            }

}

I guess the problem here is that, each time a call comes to the server, it's treated as a new request.

So how should starting and cancelling a long running task in WCF be done?

EDIT: I'm hosting it as a windows service

Bootle answered 10/3, 2013 at 17:6 Comment(2)
You'll have to store the token outside of the WCF class. The host can be restarted between WCF requests, depending on the host; so, you may have to deal with that first. You'll likely have to have some sort of other token to look up the cancellation token source that you pass in to the Stop contract.Khasi
When you say outside the WCF class, do you mean create another dll, to handle the tokens, and reference this dll by the WCF project? wouldn't it still be the same?Bootle
P
5

I have a WCF service set to PerCall

... the problem here is that, each time a call comes to the server, it's treated as a new request.

Yup, that's exactly what you're telling it to do. If you can, just change to InstanceContextMode.PerSession; then you can do what you're trying to do (assuming you're self-hosting).

If you can't do this, then you'll have to develop a more complex solution like @PeterRitchie commented. First, your host: IIS is not designed to have long-running operations independent of requests, so I'll assume you're self-hosting. Next, you'll need a form of token (like a GUID) that will act as an identifier for a long-running operation. Your Start method will allocate a GUID and CancellationTokenSource and start the operation, and your Stop method will take a GUID and use that to look up the CancellationTokenSource and cancel the operation. You'll need a shared (static, threadsafe) dictionary to act as lookup.

If your host is IIS, then your solution gets more complex... :)

First, you'll need a backend that's not hosted in IIS. Common choices are an Azure worker role or a Win32 service. Next, you'll need a reliable communications mechanism: an Azure queue, MSMQ, WebSphere, etc. Then you can build your WCF-over-IIS service to have the Start method generate a GUID identifier and drop a message on the queue to start processing. The Stop method takes the GUID and drops a message on the queue to cancel processing. All other logic gets moved to the backend service.

Poet answered 11/3, 2013 at 3:46 Comment(4)
Yes my service is hosted a a windows serviceBootle
So, I need a static dictionary, with [ThreadStatic] attribute, that stores a guid, and the cancellation object, and pull it out from the dictionary when the client next sends a call?Bootle
ThreadStatic wouldn't work. There is no guarantee that the cancelling call will run on the server as the same thread as the original calling thread. Stephen was refering to concurrency dictionaries. However I seriously suggest you look at my solution (which got downvoted) IFF you are using .net 4.5 end to end.Cerumen
@Cerumen is correct. I meant a static ConcurrentDictionary<Guid, CancellationTokenSource>.Poet
E
2

From how you've asked, the client seems to be aware of the async nature of the request.

@StephenCleary and @PeterRitchie's points are excellent, but your first step is to re-do your service/contract to properly implement an async service and add the means of communicating back (to client) some information/handle to the long running operation.

The Framework contains several paradigms for asynchronous programming (already :-) )but when it comes to WCF, you kinda fall back to How to: Implement an Asynchronous Service Operation

That will provide some infrastructure, but not necessarily the ability to automatically cancel an operation.

Speaking strictly about the cancellation (as this is your question): you will have to extend whatever your solution ends up being for cancellation. At the minimum you need to add necessary logic to your service “worker” to monitor and honor the cancellation token.

Other considerations that you may expect to encounter: return result from cancellation; cancelling a task that has managed to complete (what of you updated the 1,000,000 records by the time the cancellation request came); exception handling (with task-based programming exceptions are not thrown, but bundled in the Task, or whatever other “vehicle” you use to describe the ongoing operation).

Emoryemote answered 11/3, 2013 at 5:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.