Search code examples
azure-service-fabricservice-fabric-statefulservice-fabric-actor

Invoke Cancel manually from client side in RunAsync(CancellationToken)


In the RunAsync(CancellationToken) background method, current code is spawning new thread and also having some long running tasks inside while(true) loop.

The web api controller is exposed to provide cancel request and then using enqueue / dequeue, this request is accessed in the RunAsync(cancellationToken) while(true) loop.

I just can't make connection between the web api controller receiving this cancel request with the cancellationtoken passed down to the thread running inside runasync method.

RunAsync(cancellationToken) 
{ 
   while(True)
   { 
     new thread(cancellationtoken)
   } 
} 

One thing I am pretty sure is that there is no connection between the cancel request somehow invoked by user and the cancellationToken as argument of RunAsync() as shown in the code above. It seems they are not connected. we don't want to get out of the forever loop in RunAsync() background upon user cancel request, which is only for the specific thread run.
Please guide me to correct direction to design cancel request terminating the thread.


Solution

  • As suggested by Peter Bons, the cancellation token passed to the RunAsync, is created and managed by Service Fabric to tell a service that it is being shut down. You should watch for this cancellation to make a graceful shutdown of your services when service fabric wants to to upgrade or move the service between nodes.

    Other point is, you don't cancel CancellationToken, you cancel CancellationTokenSource, so in this case, any thread created by your code, should create a their ownCancellationTokenSource for each thread to be cancelled individually and the token generated by this CancellationTokenSource must be provided to the thread so it knows when it has been cancelled.

    Another point is, if you want make it smooth, you should create a linked CancellationTokenSource using CancellationTokenSource.CreateLinkedTokenSource(SFTokenPassedOnRunAsync) so that when Service Fabric wants to shutdown the service, the main cancellation token created will cancel any child operations, otherwise you have to handle that from your code.

    Regarding the main question, You can only cancel an Operation within the same process that created the CancellationTokenSource, The easier way is expose the an Endpoint in the Service (Via remoting or via Rest API) that will receive a call, find the token and cancel the operation.

    Would be something like:

    • The service create the CancellationTokenSource and start the new thread with the token generated
    • The CancellationTokenSource will be stored in a static variable visible within the sameprocess, so that the API can see it
    • The Api call will get this CancellationTokenSource and call Cancel()

    In case it is a list of running operations(multiple threads), you can store the CTS in a Dictionary and give IDs to each operation, then you can find the CTS based on the ID of the operation.