Finally Block — Examples
Unconditional cleanup, audit logging, resource release, and status update patterns.
01 Unconditional Audit Log with Outcome Detection
A compliance-regulated data export workflow must record every export attempt in an audit log — success or failure. The finally scope uses an If Condition to detect the outcome and writes the appropriate audit record. This single finally block replaces duplicated logging logic in both the success and error paths.
// Finally Block
[Finally Block: "finally_export_audit"]
→ [If Condition: "$mem.__exception_type__ != null"]
// true (error occurred):
→ [DB Insert: audit_log {
"workflow": "data-export",
"run_id": "{{ $ctx.workflow_instance_id }}",
"outcome": "FAILED",
"error": "{{ $mem.__exception_message__ }}",
"records_processed": "{{ $var.records_processed }}",
"timestamp": "{{ $now }}"
}]
// false (success):
→ [DB Insert: audit_log {
"workflow": "data-export",
"run_id": "{{ $ctx.workflow_instance_id }}",
"outcome": "SUCCESS",
"error": null,
"records_processed": "{{ $var.records_processed }}",
"timestamp": "{{ $now }}"
}]
02 Release Database Transaction Lock
A bulk update workflow acquires an exclusive lock on a database table at the start. The finally block unconditionally releases the lock, ensuring other workflows are never left waiting due to an exception mid-processing.
// Full trio structure:
[Try Block: "try_bulk_update"]
→ [DB: Acquire Table Lock on orders_pending]
→ [Loop: Process each order record]
→ [DB: Update order status]
→ [DB: Commit Transaction]
[Catch Block: "catch_bulk_update"]
→ [DB: Rollback Transaction]
→ [Slack: "Bulk update failed: {{ $mem.__exception_message__ }}"]
[Finally Block: "finally_bulk_update"]
→ [DB: Release Table Lock on orders_pending]
→ [Log: "Table lock released for run {{ $ctx.workflow_instance_id }}"]
03 Update Processing Status Record
A long-running document processing workflow maintains a status record in a jobs table (status: "processing"). The finally block always updates this record to either "completed" or "failed", preventing status records from permanently showing "processing" after a failure.
// Before try block:
[DB Update: jobs { status: "processing", started_at: "{{ $now }}" } WHERE id = {{ $var.job_id }}]
[Try Block: "try_document_processing"]
→ [Download Document]
→ [Extract Text]
→ [AI Classify Document]
→ [Store Results]
[Catch Block: "catch_document_processing"]
→ [Log Error: "{{ $mem.__exception_type__ }}: {{ $mem.__exception_message__ }}"]
[Finally Block: "finally_document_processing"]
→ [If Condition: "$mem.__exception_type__ != null"]
// error path:
→ [DB Update: jobs {
"status": "failed",
"completed_at": "{{ $now }}",
"error_message": "{{ $mem.__exception_message__ }}"
} WHERE id = {{ $var.job_id }}]
// success path:
→ [DB Update: jobs {
"status": "completed",
"completed_at": "{{ $now }}",
"error_message": null
} WHERE id = {{ $var.job_id }}]
04 Emit SIEM Audit Event
A security-sensitive workflow (privileged access request processing) emits a structured audit event to the organisation's SIEM platform after every execution, regardless of outcome. This is a compliance requirement — even failed attempts must be recorded.
[Finally Block: "finally_access_request_audit"]
→ [HTTP Request: POST to SIEM Event Ingestion API {
"event_type": "PRIVILEGED_ACCESS_WORKFLOW",
"workflow_id": "{{ $ctx.workflow_definition_id }}",
"run_id": "{{ $ctx.workflow_instance_id }}",
"user": "{{ $var.requestor_id }}",
"resource": "{{ $var.requested_resource }}",
"outcome": "{{ $mem.__exception_type__ != null ? 'FAILED' : 'COMPLETED' }}",
"error": "{{ $mem.__exception_message__ }}",
"timestamp": "{{ $now }}"
}]
05 Clean Up Temporary Storage Files
A report generation workflow creates several temporary files during processing (intermediate data exports, chart images, staging files). The finally block deletes all temporary files unconditionally, preventing orphaned files from accumulating in storage regardless of whether report generation succeeded or failed.
[Try Block: "try_report_generation"]
→ [Export Raw Data to temp CSV: $var.temp_csv_path]
→ [Generate Charts: store in $var.temp_chart_paths]
→ [Merge into PDF: $var.final_report_path]
→ [Upload to Report Server]
[Catch Block: "catch_report_generation"]
→ [Slack: "Report generation failed: {{ $mem.__exception_message__ }}"]
[Finally Block: "finally_report_cleanup"]
→ [File Delete: "{{ $var.temp_csv_path }}"]
→ [Loop: $var.temp_chart_paths]
→ [File Delete: "{{ $loop.current }}"]
→ [Log: "Temporary files cleaned up for run {{ $ctx.workflow_instance_id }}"]