Queueable class attaches no Finalizer

ID

apex.maintainability.queueable_finalizer

Severity

low

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Error Handling

Language

Apex

Description

Reports a class implementing Queueable whose body never calls System.attachFinalizer.

Rationale

A Queueable runs detached from whoever enqueued it, so when it throws there is no caller to catch anything: the job is marked failed in the Apex Jobs list and the work is simply not done. Nothing retries it, nothing tells the user, and the only trace is a row in a monitoring page nobody reads until a customer asks where their record went. A Finalizer is the one hook that still runs after the job’s transaction is rolled back, which makes it the only place from which a failed job can be retried, logged to a custom object, or reported.

The following code illustrates the pattern detected by this rule:

// FLAGGED: Queueable class attaches no Finalizer
public class InvoicePostJob implements Queueable {
    private Set<Id> invoiceIds;
    public InvoicePostJob(Set<Id> invoiceIds) {
        this.invoiceIds = invoiceIds;
    }
    public void execute(QueueableContext ctx) {
        List<Invoice__c> invoices = [SELECT Id FROM Invoice__c];
        update invoices;
    }
}

Remediation

Implement a small Finalizer and attach it at the top of execute: System.attachFinalizer(new MyFinalizer());. In the finalizer, branch on ctx.getResult() - re-enqueue with a bounded retry count on UNHANDLED_EXCEPTION, and record ctx.getException() where an operator will see it.

Configuration

This detector does not need any configuration.

© 2026 Xygeni. All rights reserved