TIP Error Handling with B2B Flows

I am posting this as a discrepency to something I read in GEAR. The topic is Error Handling. While I generally abide by the standards set forth in GEAR, occasionally they do not mix well with my development architecure and I need to improvise. I will not explain how GEAR describes the process.

Scenario:
A B2B Flow is called via a browser and it invokes other flows, passing variables to them. The invoked Flows may, themselves, invoke other Flows, too. Any flows may fail and that failure must be caught and passed back to the originally-called Flow. The error message must include an identifying failure message which is displayed in the end-user’s browser.

Solution:

  1. Create a top-level sequence and label it (e.g. “topLevel”). Indicate this sequence to “EXIT ON DONE”.
  2. Create a sub-sequence of “topLevel”. Label the sub-sequence “TRY”. Indicate this sequence to “EXIT ON FAILURE”. This is your TRY block.
  3. As the last step of the TRY sequence, do EXIT and EXIT FROM “topLevel” and SIGNAL “SUCCESS”.
  4. Create a sub-sequence of “topLevel”. Label the sub-sequence “CATCH”. Indicate this sequence to “EXIT ON DONE”. This is your CATCH block.
  5. In the CATCH sequence, gather the exception data by invoking “getLastError” (pub.flow:getLastError). Do not map the output to a variable.
  6. Next, create a BRANCH step and switch on the variable generated by the “getLastError” invocation named “/lastError/pipeline/errorMessage”.
  7. Create a sequence and label it $NULL. Indicate this sequence to “EXIT ON FAILURE”.
  8. In the $NULL sequence, map the string “lastError/error” to a new string variable “errorMessage”.
  9. Generate a Date-Time Stamp using “pub.date:currentDate” and map the output to a string variable named “dateTime”.
  10. Create two string variables named “errorMessage” and “serviceThrowingError”. Populate these variables with the nature of the error and with the name of the B2B Flow you are currently editing, respectively. De-select the option to “Overwrite Pipeline Variable” for “errorMessage”.
  11. As the other step of BRANCH, create a MAP step and label it “$default”.
  12. In the Pipeline Out pane, assign the following variables: errorMessage == %/lastError/pipeline/errorMessage%; serviceThrowingError == %/lastError/pipeline/serviceThrowingError%; dateTime == %/lastError/pipeline/dateTime%. Be sure to select “Perform Variable Substitution” in the dialog box.
  13. As the step following BRANCH, do EXIT and indicate the EXIT to exit from “$FLOW” and SIGNAL “FAILURE”.

As a crude graphic, the flow looks like this:

SEQUENCE: topLevel
–SEQUENCE: TRY
----[INSERT PROCESSING]
----EXIT “topLevel” and SIGNAL “SUCCESS”
–SEQUENCE: CATCH
----getLastError
----BRANCH: /lastError/pipeline/errorMessage
------SEQUENCE: $NULL
--------MAP lastError/error to “errorMessage”
--------Generate Date-Time Stamp
--------Populate variables “errorMessage” and “serviceThrowingError”
------MAP: $DEFAULT errorMessage, serviceThrowingError, and dateTime with pipeline variables
------EXIT “$FLOW” and signal “FAILURE”

If you implement this same structure in each of your B2B Flows, an error will be passed back the browser and will contain the three variables describing the state of the transaction when the error occured – errorMessage, serviceThrowingError, and dateTime.

Why doesn’t the GEAR approach work for what you’re trying to do? Primarily I’m curious about the change made to the topLevel sequence from exit on success to exit on done and adding the exit topLevel step. Seems to me that what you’ve done is functionally equivalent to GEAR but uses an extra step. What am I missing?

For those not familiar with the GEAR description of this try/catch technique, the difference between what is posted here and what GEAR describes is that the “topLevel” sequence is EXIT ON SUCCESS in GEAR rather than EXIT ON DONE. EXIT ON SUCCESS causes the topLevel sequence to be exited when the first child step, in this case the entire TRY sequence, is successful. In this configuration, the catch block will never be run when the try succeeds.

Another difference between what is in this post and what is in GEAR is the steps in the catch sequence. The steps described in the post are more robust than what GEAR describes.

I agree with Rob Eamon on this. I’ve been doing this for 2 years without a problem:

I set up all of my flows as follows:

myFlow

Sequence - Exit on Success
>>Sequence - Exit on Failure (try)
>>Squence - Exit on Done (done)

My particular setup guarantees that if my try block fails, that the catch block will catch. The catch block will complete ALL tasks prior to closing down. This enables you to abstract out writing errors to a db. If the db conn fails, perhaps you can write the errors to a log file. Once all items in catch block are “done”, the outer Sequence, set to “exit on success” will complete.