QUESTION: Can I return ActivityExecutionStatus.Faulting from a signal method to "fault" the activity?

ANSWER: As a general rule only the current status and Closed are valid return values from any of the signal methods. Therefore:

Execute() – Return values of ActivityExecutionStatus.Executing and Closed valid.
Cancel() – Return values of ActivityExecutionStatus.Canceling and Closed valid.
HandleFault() – Return values of ActivityExecutionStatus.Faulting and Closed valid.
Compensate() – Return values of ActivityExecutionStatus.Compensating and Closed valid. 

If an invalid value is returned from a singal method then the runtime will throw an InvalidOperationException which will propagate asynchronously just like any other exception occuring within the workflow.

If you are in any signal method and would like to “fault” the activity then simply throw an exception from the method. For example:

  • Execute() is called on the activity and the activity logic determines there is an error. An exception is thrown from execute.
  • The runtime will then capture the exception and pass it to the HandleFault() method of that activity. If HandleFault returns a value of Faulting then the runtime will simply continue processing the scheduler queue expecting that at some later point the activity will signal closed (see below). If HandleFault returns Closed then the runtime knows that the activity has done what it needs to handle the fault.
  • If the activity in question is composite and has a FaultHandlersActivity with a matching FaultHandler then the exception will be considered handled and will be passed to the appropriate FaultHandler. Otherwise, the exception will be passed to the parent activity’s HandleFault method and the cycle will repeat until either the fault has found a FaultHandlerActivity which matches or has left the scope of the workflow causing it to Terminate.

When would an activity want to return Faulting? Consider the case where ParallelActivity has its HandleFault method called. The parallel may have one or more currently executing branches which do not yet know about the exception. At this time, the parallel will attempt to cancel the children by subscribing to the closed status change and calling ActivityExecutionContext.CancelActivity for each child. The return value from HandleFault will be ActivityExecutionStatus.Faulting because the parallel should not closed until all of its children have cancelled successfully. Once the parallel has received close notification from each child it can then call ActivityExecutionContext.CloseActivity() to signal its own completion and cause the asynchronous exception handling to resume.