Core PHP下Webhook并发订单数据混乱问题的解决方法
How to Serialize Concurrent Webhook Requests in Core PHP
Great question—this is a classic race condition scenario when dealing with concurrent webhook requests in plain Core PHP. When multiple orders hit your endpoint at the exact same time, they can interfere with each other (like reading/processing data simultaneously) leading to corrupted records. Here's a straightforward, reliable way to serialize your order processing so only one request handles data at a time:
Solution: File-Based Mutex Locking
We'll use PHP's built-in flock() function to create an exclusive lock. This acts as a "gatekeeper"—only the request that holds the lock can process order data, while others wait until the lock is released.
Modified Code for Your order_relay Case
case "order_relay": // Define a persistent lock file path (ensure this directory is writable by PHP) $lockFile = __DIR__ . '/order_processing.lock'; // Open the lock file (creates it if it doesn't exist) $lockHandle = fopen($lockFile, 'w'); if (!$lockHandle) { // Handle lock initialization failure http_response_code(500); echo json_encode(['error' => 'Failed to initialize processing lock']); break; } // Acquire an exclusive lock (blocks until the lock is released by other processes) if (flock($lockHandle, LOCK_EX)) { try { // Your original order processing logic $body = file_get_contents('php://input'); $data = (array) json_decode($body); $orderData = (array) $data['order']->details; // Insert/update $orderData to your database (add your existing DB code here) // Send success response to the webhook sender http_response_code(200); echo json_encode(['status' => 'order_processed']); } catch (Exception $e) { // Handle processing errors (e.g., invalid JSON, DB failures) http_response_code(500); echo json_encode(['error' => 'Processing failed: ' . $e->getMessage()]); } finally { // Always release the lock, even if an error occurs flock($lockHandle, LOCK_UN); fclose($lockHandle); } } else { // Rare scenario: couldn't acquire lock (only possible if using non-blocking mode) http_response_code(503); echo json_encode(['error' => 'System busy, please retry later']); fclose($lockHandle); } break;
Key Details Explained
- Lock File: The lock file acts as a shared signal between requests. Use a fixed path (like the same directory as your script) and ensure the web server user (e.g.,
www-dataon Linux) has write permissions for this directory. - Exclusive Lock (
LOCK_EX): This flag ensures only one process can hold the lock at a time. UnlikeLOCK_NB(non-blocking),LOCK_EXmakes waiting requests pause until the lock is freed—perfect for serializing processing. - Try/Finally Block: This guarantees the lock is always released, even if an error crashes your processing logic. Failing to release the lock would cause all future requests to hang indefinitely.
- HTTP Status Codes: Returning proper status codes helps the webhook sender understand if the request succeeded. Most platforms will automatically retry requests that return 500 or 503 errors, ensuring no orders are lost.
Additional Tips
- Avoid Long Processing: Keep the code inside the locked block as concise as possible. If your database operations are slow, consider moving heavy work to a background queue (e.g., using cron jobs) to minimize wait times for subsequent requests.
- Test Concurrent Requests: Use tools like parallel
curlinstances or Postman's Collection Runner to simulate simultaneous webhook calls and verify the lock works as expected. - Lock File Cleanup: The lock file will persist even after processing—this is normal. You don't need to delete it, but you can add a cleanup step if you want (e.g., delete it after releasing the lock, though it will be recreated on the next request).
内容的提问来源于stack exchange,提问作者Rishabh Saxena
相关产品推荐
相关产品推荐

