Error Handling

Flux provides a robust error handling mechanism that allows you to define remediation steps either directly within your workflow, or through a general series of steps that can attempt to recover from the error, notify a user that the error has occurred, or display a message in the Operations Console.

Error handling is done in one of two ways: through an error flow, a specialized flow that allows you to take immediate and specific action for any errors that occur on a given step; or through an error handler, a specialized workflow that allows you to define how workflows react to errors where no error flows are available.

You can define different error handlers for different namespaces, allowing you to react to errors differently depending on the type of workflow that’s running, the priority of a workflow, and the impact that the workflow will have on the overall application.

What Happens When an Error Occurs?

If a trigger or action encounters an error, Flux does the following:

  1. Check if there is an outgoing error flow available, and if there is, follow this flow. Error flows can optionally be configured to retain or roll back any changes that the action has already made in the Flux database.
  2. If no error flow is available, find the default error handler. Flux searches the runtime configuration for the error handler closest to this workflow in the namespace tree.
  3. If the default error handler ends with an Error Action, put the workflow into the FAILED state. If it ends with any other type of action, retry the workflow from the point of failure.

Once a workflow is in the FAILED state, it will wait for a user to recover or remove the workflow from the engine.

If you haven’t installed your own error handler, Flux will use its built-in error handling mechanism, which retries the workflow up to 5 times before placing it in the FAILED state.

Error Flows

Any flow in Flux can be turned into an error flow. Error flows work the same way as any other flow — if an error occurs, Flux will follow that flow and continue executing the workflow through the path that the error flow defines.

To set up an error flow, just right-click the flow you want to use, choose “Flow Properties” from the menu, and select “Error” in the flow condition box. Once you’ve saved your changes, the error flow will be displayed in red, as with the following example:

Error Flow Example

In the example above, if the first process action encounters an error, it follows the error flow into the delay trigger, which will introduce a brief delay, then flow back into the process action. This will keep repeating until the process action runs successfully, at which point the second process action will execute.

As you can see, this makes it extremely easy to handle errors using all of the features that are already available in your workflows. This kind of targeted error handling works great in many cases, like:

  • High-priority actions that require unique error handling or remediation steps.
  • Actions where the remediation steps are known ahead of time — if an action is known to fail because a required file is missing, the error flow could lead to a file copy that retrieves the missing file.
  • Actions where alternate steps are available if the action fails — for example, using the FTP command action to transfer a file if a file copy action encounters a problem with an unusual FTP server.
  • Non-vital actions — can send an email to notify a user that the problem has occurred, then continue on in the workflow as normal.

In addition to the basic error flow condition, you can also use the following specialized conditions:

  • ERROR_WITH_ROLLBACK: Follow the error flow and roll back any changes made

If the above Java Action throws an exception, thus indicating an error, control flows into “My Error Action”, where the error can be handled appropriately. As of Flux 7.7, transactions are no longer rolled back by default; instead, error flows can be defined to rollback the current transaction. The transaction can be explicitly rolled back by using theAction.setErrorFlowWithRollback() method. Once this rollback is complete, a new transaction begins and the flow of execution continues through the specified error flow. All work in that error flow, such as runtime data mapping and signal raising, is then performed. At the end of the error flow, a transaction break is encountered and the current transaction executing in that specific error flow is committed to the database. Once the transaction in the error flow is committed, the flow will continue through the specified actions in the normal way.

From here you may set up actions to fix the problem and continue with the workflow, or you may wish to just end the workflow and exit.

In the case that an error occurs in a trigger or action and there is no error action defined, the Flux engine presumes that the workflow is finished, because there is no appropriate flow to follow. By default, the Flux engine automatically deletes workflows when they finish. This way, the database does not grow unbounded.

When an error flow is followed, there is a flow context variable generated named ERROR_RESULT. This variable can be accessed by calling flowContext.getErrorResult() in a prescript on the next action — the Error Result Data Type section below contains more information on the data available in this variable.

Error Result Data Type

The error result data type contains one field, exception. This is the original exception that caused the action to fail.

If you want to use a prescript to obtain the error message from the error result, you can call:

flowContext.put("errorMessage", flowContext.getErrorResult().exception.getMessage());

The prescript above will put the error message into a new variable called “errorMessage”, which could then be accessed through variable substitution.

Advanced Users (Java knowledge required)

The ERROR_RESULT variable, returned from flowContext.getErrorResult(), is an instance of flux.ErrorResult. This class contains one public field, exception, which is an instance of java.lang.Throwable.

You can access the exception field to retrieve information about the error, such as the message and stack trace, through standard Java APIs.

For example, to get the stack trace, you could call the following in a prescript on the action following the action that caused an error:

flowContext.getErrorResult().exception.getStackTrace();

Custom Error Handlers

The above section describes how to create an error flow to handle errors that occur when a trigger or an action executes. An error flow handles an error in a specific trigger or action in a specific way. To handle specific situations with a specific error flow, an error flow must be defined at each trigger or action for each specific situation.

On the other hand, default workflow error handlers have a broad scope. A single error handler can be defined in one location. That error handler can be responsible for recovering from errors, retrying actions, sending notifications, and performing other error recovery actions.

By default, a default error handler is installed that retries actions up to five times, with one-minute delays in between. If the action still fails after five retries, the execution flow context is placed into the ERROR super-state and the PAUSED sub-state.

Default error handlers are simply workflows that are installed in the runtime configuration tree. When an execution flow context executes an action and that action throws an exception, if no error flow is defined, the Flux engine searches for a default error handler.

The Flux engine checks the hierarchical workflow namespace in the runtime configuration tree, beginning at the location in the tree that corresponds to the name of the workflow and working its way to the root of the tree. The first default error handler that is found is used. If no error handler is found, the workflow is considered to be finished, in which case the workflow terminates and is deleted in the normal way whenever a workflow finishes.

However, if a default error handler is found, the following actions take place.

  • The execution flow context’s transaction is rolled back.
  • The execution flow context’s super-state is changed from NORMAL to ERROR.
  • The execution flow context creates the default error handler workflow and begins executing it.
  • If the error handler workflow terminates normally, without throwing an exception, the execution flow context commits the current transaction and resumes execution in the main workflow from the point of the last committed transaction.
  • On the other hand, if the error handler workflow terminates by throwing an exception, the execution flow context commits the current transaction, and the main workflow is placed into the PAUSED state. Because paused workflows do not execute when paused and because this workflow is in the ERROR super-state, extraordinary actions can be performed in an attempt to remedy the workflow and ultimately resume it.
  • Whenever a workflow action is retried after an error, runs successfully to a transaction break, and successfully commits the transaction, the execution flow context’s super-state is changed back from ERROR to NORMAL, and the error handler workflow instance is destroyed.

As with error flows, when a default workflow error handler is entered, Flux creates a flow context variable called ERROR_RESULT. See Error Result Data Type above for more information.

Basically, Flux does the following when an error is encountered:

  • Check for an error flow. If there is no error flow, use the default error handler.
  • “Insert” the default error into the workflow at the point of failure. Execute the default error handler workflow as usual.
  • If the default error handler ends in an error action, the main workflow enters the failed state. Any message entered in the “Message” property of the Error Action in the default error handler is displayed in the “Message” column on the Operations Console’s workflows page.

If it ends in any other type of action, the main workflow is retried from the point of failure.

Error handling can be done either inside the workflow using error flows or it could be abstracted outside the workflow using custom error handlers.

In order to define a custom error handler, you need to define the following configuration in the Flux runtime configuration file:

/DEFAULT_FLOW_CHART_ERROR_HANDLER=/opt/flux-7-9-9/fluxproject/Custom Error Handler.ffc

Error handlers are defined per namespace in the runtime configuration file. An error handler on a namespace branch will take precedence over any error handlers set on higher branches.

/client1/data flow/DEFAULT_FLOW_CHART_ERROR_HANDLER=/opt/flux-7-9-9/fluxproject/Custom Error Handler1.ffc
/client2/data flow/DEFAULT_FLOW_CHART_ERROR_HANDLER=/opt/flux-7-9-9/fluxproject/Custom Error Handler2.ffc

For a complete working example demonstrating a custom error handler, refer to the /examples/end_users/error_handling directory under your Flux installation directory.

Displaying the Name of the Action that Caused an Error

As mentioned above, the grid on the workflows page of the Operations Console has a “Message” column that displays the value of the “Message” field in the final Error Action of the default error handler for any workflows in the FAILED state. You can use this to report information about the error back to the Operations Console; for example, you could report the name of the action in the main workflow that originally caused the error (which, by default, is not displayed).

This requires two steps: first, on the Error Action in your default error handler, add the following prescript:

flowContext.put("errorActionName", flowContext.getErrorResult().throwingAction);

This prescript gets the name of the action that originally caused the error (obtained by calling flowContext.getErrorResult().throwingAction), then adding that value as a new flow context variable, “errorActionName” (you can change this to another name if you would prefer).

Next, set the Error Action’s “Message” property and using variable substitution, include the value of the flow context variable you just set. When you’re finished, the message property should look like this:

The action ${errorActionName} caused an error.

Now, when a workflow invokes the default error handler and eventually enters the FAILED state, you will see a message on the console like “The action MyActionName caused an error.”