Automatically Handle Failures in Tasks
This topic provides information about how to automatically handle failures in Release tasks.
By default, when a task in a release fails, the release stops so you can retry the task, skip the task, or add new tasks to resolve the issue. If the Abort on failure option is selected, the release immediately aborts if a failure occurs. This is useful for Continuous Integration/Continuous Delivery environments in which a new code commit will fix the problem and start a new release.
These options provide general support for both fully and partially automated release scenarios. In some scenarios, you may want to execute certain actions if a task fails; for example, cleaning up resources or notifying a certain team. This topic will describe two approaches:
Release has property on the task level called Handling failure. You can use this to execute a Jython
script when the task fails its execution or just to skip the task. For more information, see Task failure handler.
The examples shown here are based on a sample template that you can download and import.
This requires adding a custom task type, which you can do by copying the type definition to the ext
directory or by downloading and installing this community plugin.
The code provided in the Gist is sample code that is not officially supported by Digital.ai. If you have questions, please contact the Digital.ai Support team.
Handling failure in the task
The simplest and most effective way to handle failure in a task is to include the appropriate error-handling logic in the task implementation itself. For example:
This approach allows you to retry the task multiple times without accumulating a backlog of items that need to be cleaned up later. Example: If a task tries to create a user and then create a ticket, you can add a failure handler around the "create ticket" part so you can delete the user if the ticket was not created successfully. Replace this section:
newUser = createUser()
ticket = createTicket(newUser)
With this logic:
newUser = createUser()
try:
ticket = createTicket(newUser)
except:
deleteUser(newUser)
sys.exit(1)
You can use this approach with Remote Script tasks, Jython Script tasks, and custom tasks. Example of a Remote Script task:
Handling failure in a conditional block
In cases where the task implementer does not know which actions need to be taken when a task fails, you can add a group immediately following the task with a condition that ensures that it only executes if the task does not succeed. For example:
In this case, the task must:
-
Complete its executing without triggering a task failure. A Remote Script task must exit with a non-zero exit code, and a Jython Script task must not throw an exception.
-
Set the value of a variable to an appropriate value for the conditional group to determine if it should execute. In some cases, this can occur by default Examples: There can be a standard output or error. For HTTP requests, you may want to expose the response code for this purpose.
Sample Jython Script task
This is an example of a Jython Script task that succeeds and sets a variable with the response code of the HTTP request it executes.
The associated group then checks the variable in its precondition.
If you want the release to fail after the cleanup operation is done, add a task that fails to the end of the conditional group.
Sample Remote Script Task
For Remote Script tasks, you can determine if a task succeeded by looking at the standard output or standard error, which are available as variables.
For remote tasks, you can to determine if a task did not succeed by looking at the standard out or standard error, which are already available as variables.
The remote script is configured to always return exit code 0, so the Release task will not fail:
Sample custom Webhook task
This approach can be used with other task types, with some customizations. Example: This sythetic.xml
code extends the Webhook task type with a type that always succeeds and provides the HTTP response code as an output variable that can be used in subsequent tasks.
<type type="acme.JsonWebhook" extends="webhook.JsonWebhook">
...
<property name="statusCode" kind="integer" category="output" required="false"
description="The HTTP status code of the response" />
<property name="alwaysSucceed" kind="boolean" category="input"
required="false" default="false" description="If checked, this task will
succeed irrespective of the HTTP response code. The 'statusCode' output
property can be checked by subsequent tasks to determine whether the call
was actually successful." />
</type>
This also requires minor changes to the implementation:
You can use the modified Webhook task with a group that checks the status code to determine if the task executed successfully.
The type definition and task implementation are available as part of the Gist mentioned above.
The code provided in the Gist is sample code that is not officially supported by Digital.ai. If you have questions, please contact the Digital.ai Support team.