Urgent.News

What's breaking now, across thousands of outlets.

Tech

How a Timeout Can Charge Your Customer Twice (And How to Stop It in Laravel)

A customer attempts a payment. The request safely reaches your server, and the transaction is performed successfully. Then, while the response is being sent back to the client, the connection drops. The client never receives a success message. Instead, they see a timeout. The client has no possible way of knowing if the charge went through or not, so they logically retry. This is where problems…

When a customer attempts to make a payment, the request successfully reaches your server and the transaction is completed. However, if the client's connection drops during the response transmission, they receive a timeout error. Since the client cannot determine if the payment was successful or not, they retry the payment. This leads to a situation where the server receives a second POST request for the same payment, unaware if it was charged before. If the system doesn't handle this scenario correctly, the customer ends up being charged twice.

An idempotency key, typically a unique identifier like a UUID, is used to represent a specific payment transaction. It is generated by the client and stored along with the request. When a client retries the payment due to a timeout, it uses the same idempotency key instead of creating a new one. The server checks if the transaction has been processed before by verifying the idempotency key.

The naive approach to handling this scenario involves checking if the idempotency key exists in the database. If it doesn't, the payment is processed and the key is saved in the database. However, this approach has a significant flaw. Since servers can handle multiple requests simultaneously, if two requests arrive at the same time, both could check for the existence of the key before either one saves it. This results in both requests being processed simultaneously, leading to double charges.

The solution to this issue is atomic locking. Instead of checking for the key's existence and saving it as separate steps, the check and save must happen together as one process. Laravel's Cache::lock() method is used to achieve this. It blocks the request for a certain period of time, allowing the first request to finish processing.

Once the first request is done, the result is reused. If another request attempts to process the payment during this time, it is blocked until the first request is complete. This ensures that double charges are impossible.

It's also important to store the response along with the idempotency key, not just the key itself. This is crucial because if the client retries the payment, they need to receive the exact same response that was supposed to be sent back in the original request. This makes the retry appear as a normal, successful request to the client.

Additionally, idempotency keys should not be stored indefinitely. They should have a time-to-live (TTL), often set to 24 hours, to prevent unnecessary storage and ensure old keys are deleted. This can be implemented in Laravel using a scheduled job that scans the database for old keys and deletes them.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

Client API Key — Design (Lite) ออกแบบ API key service to service ให้เบาและยังถูกต้อง

ออกแบบ API key สำหรับการเรียกกัน service to service ให้เบาและยังถูกต้อง วันหนึ่งจะมีอีกทีมมาขอเรียก service ของคุณ และคุณต้องรู้ให้ได้ว่าใครเป็นคนยิงเข้ามา ตัวเลือกที่คนส่วนใหญ่หยิบมีสองขั้ว…

  • Lightweight API key service designed for service-to-service communication
  • Six columns and ten functions in the CREATE TABLE statement
  • Keys revoked using timestamps, not stored directly in the database

Shopify or WooCommerce? How I Chose My First E-Commerce Platform

When I first started thinking about opening an e-commerce store, my first question was simple: Shopify or WooCommerce? At first, Shopify looked like the obvious choice.

  • Shopify offers simplicity with included hosting and minimal technical concerns.
  • WooCommerce provides control over hosting, plugins, and custom integrations.
  • Decision hinges on preference for simplicity vs. control in managing an e-commerce store.

More from Saturday 29 August →