In this guide 6 sections
Trace one order from the payment callback to the confirmation page and time every step, hunting for an invoice PDF, email or stock sync running inside the request. Move it to a background job. The shopper then sees the confirmation within a second or two, while the invoice and email follow quietly from a worker process.
Place one test order and time every step
Make a real order for a small amount, or use the gateway’s test mode, with the browser developer tools open on the Network tab. Note the request that takes longest after the payment page returns, because that single slow line is your first clue to the cause.
Then switch on timing in the application log. Write a line carrying the order id at the start and end of each step, so you can rebuild the sequence afterwards. Without per-step timing you are guessing.
Repeat the order three times. A step that is slow once may be a cold start, while a step that is slow every time is your target.
Follow the callback through each stage
After payment, the gateway sends the customer back to your site and also calls a webhook on your server, which then runs the remaining jobs. It marks the order paid, reduces stock, creates the invoice and sends the messages, one after another inside a single request handler.
Each stage has its own delay. Number the stages in code order. Write the time beside each.
The slow stage is often the one that talks to someone else, because an outside call takes as long as the other side takes to answer. Tuning your own code will not help.
- Verify the gateway signature and mark the order paid
- Reduce stock, or sync it with a warehouse system
- Build the invoice PDF and store the file
- Send the confirmation email and WhatsApp or SMS
- Push the order to a courier or accounts package
Spot the call that blocks the page
Look for work that need not finish before the shopper sees a confirmation, such as the invoice PDF and the email, which nobody needs that second.
Check for missing timeouts. A call to an SMS provider with no timeout can hang for a minute when the provider is struggling, and the shopper stares at a spinner.
Keep what must happen now, which is confirming the payment and reserving the stock, and let everything else wait a few seconds behind a queue. Seconds of delay do no harm.
Move it to a background job without losing the confirmation
Write a row in a jobs table, or add a message to a queue such as Redis, SQS or RabbitMQ, and then return the confirmation page at once. The worker does the slow part, whether that is rendering the invoice PDF or calling the SMS provider, while the shopper reads the confirmation.
Make every job safe to run twice. Gateways retry webhooks, so one payment can arrive twice, which is why you store the gateway’s payment id and skip anything already handled.
If a job fails, retry it a few times with a growing delay, and after that park it on a failed list that a person reviews each morning. No order should silently lose its invoice.
- Queue name and retry count for each job type
- Payment id stored to block duplicate processing
- A failed jobs screen the support team can open
- An alert when the queue grows past a set size
Confirm the fix with the same test order
Place the test order again. Compare against your first notes. The confirmation should now appear within a second or two, and the invoice and email should follow a little later without the shopper waiting for them.
Then test the failures. Retry the webhook. Switch off the email provider. Slow down the warehouse API. The shopper should still see a confirmation every time, because that is the pass mark for this fix and for every later change.
Keep the timing lines in the log. They are the cheapest early warning you will have, because the day someone adds a new step to the callback the totals will drift upward.
Order trace sheet
A one-page table follows one order, with rows for the stages after payment: signature check, order paid, stock update, invoice, email, message and courier push. Columns: start time, end time, seconds taken, external or internal, blocks the page yes or no, and the decision to keep, queue or drop.
Open a blank worksheet to printQuestions owners ask
Why does the page hang only sometimes?
Usually an outside service is slow that day, such as an email or SMS provider, a courier API or the gateway itself answering late. Add a timeout and a queue.
Will a queue delay the invoice for the customer?
By a few seconds in most setups, so the customer sees the confirmation at once and receives the invoice shortly after, which beats staring at a spinner.
What if the customer pays but the page never returns?
The webhook still marks the order paid. Offer a status page that checks the order, so a refresh or a later visit shows the result without any second payment attempt from the shopper. Never ask the customer to pay twice.
