Make It Asynchronous (Queueable)
By the end of this lesson, you'll be able to:
- Wrap PaymentGatewayService in a Queueable job
- Enqueue the job from a trigger handler
- Update the Order record with the result from inside the Queueable job
Prerequisites: "Build the Callout Service"
The Queueable wrapper
public class ProcessPaymentJob implements Queueable {
private Id orderId;
private Decimal amount;
private String paymentToken;
public ProcessPaymentJob(Id orderId, Decimal amount, String paymentToken) {
this.orderId = orderId;
this.amount = amount;
this.paymentToken = paymentToken;
}
public void execute(QueueableContext context) {
PaymentResult result = new PaymentGatewayService().charge(amount, paymentToken);
Order__c order = new Order__c(Id = orderId);
if (result.success) {
order.Status__c = 'Paid';
order.Payment_Reference__c = result.gatewayTransactionId;
} else if (result.declined) {
order.Status__c = 'Payment Declined';
order.Decline_Reason__c = result.message;
} else {
order.Status__c = 'Payment Error';
}
update order;
}
}
This is Module 38's Queueable pattern doing genuinely real work: execute() calls the synchronous-looking PaymentGatewayService (which is fine now, since it's running in its own async transaction, not inside the original trigger), then updates the Order__c based on Lesson 2's typed result.
Enqueuing from the trigger handler
public class OrderTriggerHandler {
public void afterUpdate(List<Order__c> newOrders, Map<Id, Order__c> oldMap) {
for (Order__c order : newOrders) {
Order__c oldOrder = oldMap.get(order.Id);
Boolean justReadyForPayment = order.Status__c == 'Ready for Payment' && oldOrder.Status__c != 'Ready for Payment';
if (justReadyForPayment) {
System.enqueueJob(new ProcessPaymentJob(order.Id, order.Total__c, order.Payment_Token__c));
}
}
}
}
This is Module 24's Trigger.oldMap transition-detection pattern (from Module 26's rollup) combined with Module 38's System.enqueueJob — the trigger itself never makes a callout at all, it only ever enqueues asynchronous work.
Exercise
As a comment, trace through why OrderTriggerHandler.afterUpdate never violates the "no synchronous callouts in a trigger" rule.
Show hint
Look at exactly what happens inside afterUpdate itself.
Make It Asynchronous (Queueable) Quiz
My Notes
Log in to keep private notes on this lesson.
Questions about this lesson
No questions yet — be the first to ask.
Log in to ask a question about this lesson.
Summary
This lesson wraps Lesson 2's service in a Queueable job — Module 38's pattern, applied to make the synchronous-looking service actually usable from a trigger.