# Finalize your Tekton Pipeline Tekton Pipeline [0.14](https://github.com/tektoncd/pipeline/releases/tag/v0.14.0) introduced a new section `finally` in the `pipeline` specifications. This new section is ideal for running anything just before exiting the pipeline, for example, cleaning up any acquired resources, sending notifications, rolling back deployments, and etc. As it's defined on the Tekton [website](https://tekton.dev/docs/pipelines/pipelines/#adding-finally-to-the-pipeline), `finally`section takes a list of one or more tasks which are all executed in parallel after all `tasks` are finished executing regardless of a success or a failure. ![](https://i.imgur.com/XyE9SiE.gif =300x) Also, the execution status of a `finally` task affects the overall `pipelineRun` status. A `pipelineRun` is declared failed if one or more `finally` tasks fail. We have implemented many features over the past few releases to help design `finally` tasks for common use cases. ## `finally` Use Cases Tekton pipeline is implemented as a Kubernetes controller and executes a collection of `pods` on your Kubernetes cluster. A `pipeline` can be configured using a `dag` (Directed Acyclic Graph) and a set of `finally` tasks based on your CI/CD workflow. Some of the common CI/CD workflows include `build-test-deploy`. Let's extend this most common workflow to include complex `finally` scenarios. ### Send Notification A CI/CD `pipeline` defines a `finally` task `send-notification` referencing [send-to-channel-slack](https://github.com/tektoncd/catalog/tree/main/task/send-to-channel-slack) and/or [sendmail](https://github.com/tektoncd/catalog/tree/main/task/sendmail) to notify the team and send success or failure notification depending on the execution status of the build process. The build process includes [build](https://github.com/tektoncd/catalog/tree/main/task/golang-build) and [test](https://github.com/tektoncd/catalog/tree/main/task/golang-test) tasks in the `tasks` section of the `pipeline`. ![](https://i.imgur.com/AI5EPzm.png) ### Cleanup Resources A couple of cleanup scenarios: * A `pipeline` creates project or acquires resources and sends the name of that project/resources to the `finally` task. The `finally` task can then clean up those project resources regardless of a failure in `tasks` section. * A `pipeline` provisions a new k8s cluster. The `pipeline` starts executing and stopped for some reason. The `pipeline` has defined `finally` tasks to free up the k8s cluster. Even though the `pipelineRun` is stopped, the `finally` section should be executed to free up the resources. ![](https://i.imgur.com/CpX6mbL.png) ### Terminate rather than Cancel While running a `pipeline` which executes a few ETL (Extract, Transform, and Load) processes in a sequence, due to resource constrains, I would like to cancel scheduling any further process but compelete executing the current running process and analyze the results from that process. ![](https://i.imgur.com/5NS178z.png) We just explored the most common use cases which requires `finally` or `exit handler` kind of functionality in a `pipeline`. Next, let's look at the list of the features we introduced to accomplish these use cases. ## `finally` with `if` The `finally` tasks are guaranteed to execute before the `pipelineRun` exits. Now, there are use cases where the `pipeline` needs flexibility to not run a `finally` task based on a certain condition, for example, the user wants to send a slack notification only if a build fails. We have implemented two features to make this use case possible. [TEP-0045](https://github.com/tektoncd/community/blob/main/teps/0045-whenexpressions-in-finally-tasks.md) and [TEP-0028](https://github.com/tektoncd/community/blob/main/teps/0028-task-execution-status-at-runtime.md) has more details. The overall idea here is to enable specifying `when` expressions in a `finally` task and providing a means to access the execution status of a `task` in a `finally` task at runtime to evaluate specified `when` expressions. An execution status of a task can be accessed using a context variable `$(tasks.<task-name>.status)`. ```yaml= spec: pipelineSpec: tasks: - name: golang-build taskRef: name: golang-build - name: unit-test taskRef: name: golang-unit runAfter: [ golang-build ] - name: deploy taskRef: name: deploy runAfter: [ unit-test ] finally: - name: notify-build-failure when: - input: $(tasks.golang-build.status) operator: in values: ["Failed"] taskRef: name: send-to-slack-channel ``` Now, instead of notifying just a build failure, the user wants to send a slack notification for any failure. [TEP-0049](https://github.com/tektoncd/community/blob/main/teps/0049-aggregate-status-of-dag-tasks.md) implemented accessing an aggregate status of the `tasks` section in `finally` using a context variable `$(tasks.status)`. ```yaml= spec: pipelineSpec: ... finally: - name: notify-any-failure when: - input: $(tasks.status) operator: in values: ["Failed"] taskRef: name: send-to-slack-channel ``` ## Connecting `tasks` and `finally` sections A `pipeline` author can now send the execution results of a task to any `finally` task so that the project resources created/acquired by the `pipeline` are guaranteed to be cleanup up by the `finally` task. The design details of this feature are in [TEP-0004](https://github.com/tektoncd/community/blob/main/teps/0004-task-results-in-final-tasks.md). ```yaml= spec: tasks: - name: acquire taskRef: name: acquire finally: - name: release taskRef: name: release params: - name: leased-resource value: $(tasks.acquire.results.leased-resource) ``` ## Gracefully Terminating a `pipeline` [Rafal Bigraj](https://developer.ibm.com/profiles/rafal.bigaj/) spent a lot of effort in designing and implementing a feature ([TEP-0058](https://github.com/tektoncd/community/blob/main/teps/0058-graceful-pipeline-run-termination.md)) which made one of the common machine learning use cases possible using [Tekton](https://tekton.dev/). We implemented a solution to enable graceful termination (cancellation) of a `pipeline` in which the current running `tasks` are cancelled or terminated and the cleanup is scheduled. When a `pipelineRun` is executing, the users can update its definition to cancel the `tasks` which deletes all the respective pods and schedule `finally` section. ```yaml= apiVersion: tekton.dev/v1beta1 kind: PipelineRun metadata: name: etl-processes spec: status: "CancelledRunFinally" ``` We implemented one more solution to let the running `tasks` finish but no new `tasks` are scheduled and after the current running `tasks` finish, the `finally` section is executed. ```yaml= apiVersion: tekton.dev/v1beta1 kind: PipelineRun metadata: name: etl-processes spec: status: "StoppedRunFinally" ``` We just reviewed how a `finally` section of the `pipeline` is designed to implement various use cases. If you have any such use case or need and looking for a new feature in Tekton, please reach out to the community over [Slack](https://github.com/tektoncd/community/blob/main/contact.md#slack) or please feel free to open a discussion in the [tektoncd/pipeline](https://github.com/tektoncd/pipeline/discussions) repo. Thank you for stopping by!