CharlieDigital

It seems like there must be some way to cancel workflows spawned from an InvokeWorkflowActivity.

I currently have two sequential workflows set up such that one workflow performs a set of intialization activities and then at some point, in a ReplicatorActivity, I execute an InvokeWorkflowActivity for a given number of times.

The InvokeWorkflowActivity operates asynchronously such that as soon as it executes, it completes (does not wait for spawned workflow to complete).

Once the ReplicatorActivity finishes, I have a WhileActivity with a HandleExternalEventActivity which receieves notifications from the spawned workflows that they've completed.

In some scenarios, though, let's say only one of the spawned workflows needs to complete. In such a scenario, I'd like to cancel the other workflows from the root workflow (the HandleExternalEventActivity).

I haven't been able to find a way to cancel the spawned workflows. It would seem logical to have the spawned workflow also have a HandleExternalEventActivity via which the root workflow could send a signal to cancel. But even then, how would I get the reference to the ActivityExecutionContext to cancel the workflow activity Also, in the case of a sequential worklow, where would the HandleExternalEventActivity be placed (since it applies to the entire workflow activity and not in a particular location in the sequence)

Any insight would be appreciated :-)




Re: Windows Workflow Foundation Cancelling Workflows Spawned From InvokeWorkflowActivity

Vignesh Kannappan

Since we do not permit explicitly controlling other workflows from within a workflow (by design), you could try to send a message to the workflow runtime with the instanceid of the spawned workflow you are trying to cancel and have the runtime abort it.

Parent Workflow -> InvokeWorkflow: creates a new workflow and its Guid is populated into InstanceId property of the InvokeWorkflowActivity. Define a method on the external data exchange service that takes in a Guid , have the parent workflow invoke this method when it wishes to cancel a particular workflow. In the service thread with a reference to the runtime you should be able to grab the spawned workflow using the GetWorkflow() on the runtime and simply invoke the Abort() method on the returned WorkflowInstance.

Let me know if this approach works.

Vignesh






Re: Windows Workflow Foundation Cancelling Workflows Spawned From InvokeWorkflowActivity

Angel Azcarraga - MSFT

One thing to be careful with abort is that if the workflow has already persisted before the runtime gets to call abort on it, it will continue executing from the previous persistence point, which is not what you're necessarily looking for.

You'll need to call Terminate() if you want to ensure that the workflow completes immediately and does not attempt to re-execute.






Re: Windows Workflow Foundation Cancelling Workflows Spawned From InvokeWorkflowActivity

Priyanka Choughule

hi angel

will u please explain how to call Terminate();





Re: Windows Workflow Foundation Cancelling Workflows Spawned From InvokeWorkflowActivity

CharlieDigital

Thanks for the replies.

I tried the Abort() route, but since I do not have persistence set up yet, it barfed in my face :-P (I'm working on this as a "reference" implementation so it's a simple console app. to demonstrate the communications and design patterns mostly).

Ultimately, I ended up overriding the Closed event of the InvokeWorkflowActivity (which resides in the Replicator).  I then grab the InstanceId from the spawned workflow (available as a property of the InvokeWorkflowActivity instance at this point) and I put it into a list.  Then, as suggested, I pass this up to the runtime via an ExternalDataExchangeService and I Abort() them from the host.  But of course, as I said, this doesn't work without a persistence service and doesn't seem like the right thing to do anyways (but is there a way to cancel it)

I'll look into the Terminate(), but I can't help think that there should be a more "friendly" solution that would allow me to perform a true Cancel() on the spawned workflows (since the workflow itself is an Activity...). 

Vignesh, I guess then, a better question to ask is whether there is perhaps a better design pattern for what I'm trying to accomplish.  You see, I have an "outer" sequential workflow that is responsible for performing some setup and teardown of an environment.  Once the setup is complete, it launches "inner" state machine workflows (via ReplicatorActivity) which it allows to complete (but sometimes, only m of n have to reach completion for the entire set to be considered complete.  After completion, the outer workflow performs the teardown of the environment.  Instead of separating the two workflows, I'm thinking perhaps the right thing to do is to model it as a single squential worklfow that uses a ListenActivity in a WhileActivity with a condition based on a string property of the workflow and one of the strings will be designated the "ending state".

So something like:


CodeActivity (setup)
    -> ReplicatorActivity
        -> WhileActivity (for each instance, while not in an "ending" state name)
            -> ListenActivity (handle specific events and "transition" into a new "state")
CodeActivity (teardown)

-edit- So I tried the terminate and the results are a bit better.  But it still raises the same message regarding the persistence service, which is not a deal breaker, but is there really no way to "destroy" or "discard" a workflow

As well, when I try to call back through the service to terminate the workflows at the runtime, I am receiving the following exception:

 System.Workflow.Activities.EventDeliveryFailedException was caught Message="Event \"OnCancellingWorkflows\" on interface type \"WorkflowSample.EventServices.ICancelWorkfowService\" for instance id \"a7489c1b-014e-4640-9a30-ad065bf3cf3f\" cannot be delivered." Source="System.Workflow.Activities" StackTrace: at System.Workflow.Activities.WorkflowMessageEventHandler.EventHandler(Object sender, ExternalDataEventArgs eventArgs) at System.EventHandler`1.Invoke(Object sender, TEventArgs e) at WorkflowSample.EventServices.CancelWorkfowService.CancelWorkflows(Guid ownerId, List`1 workflowIds) in F:\Projects\Sandbox\WorkflowSample.Source\WorkflowSample\EventServices\ICancelWorkflowService.cs:line 33

{"Event Queue operation failed with MessageQueueErrorCode QueueNotFound for queue 'Message Properties\r\nInterface Type:WorkflowSample.EventServices.ICancelWorkfowService\r\nMethod Name:OnCancellingWorkflows\r\nCorrelationValues:\r\n'."}
    [System.InvalidOperationException]: {"Event Queue operation failed with MessageQueueErrorCode QueueNotFound for queue 'Message Properties\r\nInterface Type:WorkflowSample.EventServices.ICancelWorkfowService\r\nMethod Name:OnCancellingWorkflows\r\nCorrelationValues:\r\n'."}
    Data: {System.Collections.ListDictionaryInternal}
    HelpLink: null
    InnerException: null
    Message: "Event Queue operation failed with MessageQueueErrorCode QueueNotFound for queue 'Message Properties\r\nInterface Type:WorkflowSample.EventServices.ICancelWorkfowService\r\nMethod Name:OnCancellingWorkflows\r\nCorrelationValues:\r\n'."
    Source: "System.Workflow.Runtime"
    StackTrace: "   at System.Workflow.Runtime.WorkflowQueuingService.GetQueue(IComparable queueID)\r\n   at System.Workflow.Runtime.WorkflowQueuingService.EnqueueEvent(IComparable queueName, Object item)\r\n   at System.Workflow.Runtime.WorkflowExecutor.EnqueueItem(IComparable queueName, Object item, IPendingWork pendingWork, Object workItem)\r\n   at System.Workflow.Runtime.WorkflowInstance.EnqueueItem(IComparable queueName, Object item, IPendingWork pendingWork, Object workItem)\r\n   at System.Workflow.Activities.WorkflowMessageEventHandler.EventHandler(Object sender, ExternalDataEventArgs eventArgs)"
    TargetSite: {System.Workflow.Runtime.EventQueueState GetQueue(System.IComparable)}






Re: Windows Workflow Foundation Cancelling Workflows Spawned From InvokeWorkflowActivity

Angel Azcarraga - MSFT

Priyanka,

Terminate is called the same was as Abort() - it's a method on the WorkflowInstance class.






Re: Windows Workflow Foundation Cancelling Workflows Spawned From InvokeWorkflowActivity

Angel Azcarraga - MSFT

Charlie,

So Abort is definitely not the route you want to take here. Though Terminate gets the job done, it indeed is not a graceful exit and does not really conform with your scenario either.

If your invoked workflows are state machine workflows, then it's really easy to model a graceful exit or "cancel." You should add a top-level (workflow level) event handler (EventDrivenActivity) that listens for a "cancel" event, like the one on your ICancelWorkflowService. You continue with the pattern that you and Vignesh have worked on, by which you send all the target instance IDs to your local service via a CallExternalMethodActivity, and from the body of that target method, you grab the WorkflowInstance for each target workflow to cancel and call the cancellation event. Your top-level handler will respond to the event by simply transitioning to the completed state, which will automatically result in a cancellation of everything else, and the workflow will complete gracefully.

Does this make sense

-Angel






Re: Windows Workflow Foundation Cancelling Workflows Spawned From InvokeWorkflowActivity

Vignesh Kannappan - MSFT

Charlie - As Angel says terminate() is more suitable than abort(), however you may wish to rollback any changes the workflow has done so far to the state of the application. In addition to just having the state machine workflow transition to one of the final states, I think you would also need to undo the changes done so far. This is very specific to the paritcular app being authored and would need to be done very carefully.

_Vignesh






Re: Windows Workflow Foundation Cancelling Workflows Spawned From InvokeWorkflowActivity

CharlieDigital

Yes, this makes sense.  You know what happens, though, sometimes when you're working on stuff like this, you get sidetracked when you stumble upon something interesting  I figured it would be more straightforward with a state machine workflow so it's good to get some feedback on this, but I haven't tried it yet - I was too engrossed with how such a situation would be done with a sequential workflow (even though the scenario I'm modelling calls for a state machine).

It would seem like that the WorkflowInstance (or perhaps WorkflowRuntime ) should have a CancelWorkflow()/ForceCancel()/ForceComplete() and support cancellation semantics in some way (since the workflow itself is an Activity).

Thanks for the info, this thread helped a lot!