Automatically handle failures in 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:
- Handling failure in the task
- Handing failure in a conditional block, based on the task status/output
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.
Note: 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 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)
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.
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.
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. Note: The remote script is configured to always return exit code 0, so the Release task will not fail:
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.