ARTICLE AD BOX
I have a process that was working as expected until I migrated my dev environment from wampserver to laragon.
Now I am using Laragon v8.2.3 on Windows 10 Pro with:
php-8.3.16 [TS]
Nginx 1.27.3
Guzzle 6.5.5
cURL 8.7.0‑DEV
I have a php process that:
Get an email from inbox
Validate against DB and get dealer details
Connect to endpoint to get a stockId createStockFeed()
Use the resulting stock_id to connect to endpoint and pass the feed postStockFeed()
Problem is that the connection never closes or times out unless I kill the web server. So I added
'timeout' => 10, 'connect_timeout' => 5,to the `$httpClient->post()` and now it disconnects force-ably after the 10 seconds on every 2nd connection. Every 2nd connection appears to disconnect gracefully
cURL error 28: Operation timed out after 10003 milliseconds
I want it to disconnect gracefully on all connections but I dont know what it is about this environment that is creating this issue.
foreach ($emailMIDs as $mid) { ... $stockFeedId = $this->customer->createStockFeed( $dealerId ); if ( $stockFeedId ) { $postResult = $this->customer->postStockFeed( $stockFeedId, $dealerId, $this->attachment ); } ... }class: Customer
function getHttpClient() { if (!$this->httpClient) { $this->httpClient = new Client([ 'base_uri' => 'http://localhost', 'headers' => [ 'Content-Type' => 'application/json', 'apikey' => 'P9SAa5RJTk9waUJW9gzD', ] ]); } return $this->httpClient; } function createStockFeed($dealerId) { $client = $this->getHttpClient(); $timestamp = date('YmdHis'); $referenceId = $dealerId . $timestamp; try { error_log("About to POST to mock.api.php for $dealerId"); $response = $client->post( 'mock.api.php', [ 'json' => [ 'region' => 'au', 'reference_id' => $referenceId ], 'timeout' => 10, 'connect_timeout' => 5, ]); $data = json_decode($response->getBody(), true); if (isset($data['stock_feed_id'])) { error_log( "Stock Feed ID Created: " . $data['stock_feed_id']. " (with referenceId: $referenceId)" ); return $data['stock_feed_id']; } else { error_log( "Error: stock_feed_id not found in response: ".print_r($data,true) ); return false; } } catch (RequestException $e) { error_log( "Error creating stock feed: " . ($e->hasResponse() ? $e->getResponse()->getBody()->getContents() : $e->getMessage()) ); var_dump($client); return false; } } public function postStockFeed( $stockFeedId, $dealerId, $attachment ) { $stockFeed = $this->transformVehicleData($attachment->getDataArray()); $client = $this->getHttpClient(); foreach ($stockFeed as $stock) { $stockNo = $stock["stock_no"]; try { error_log("Lets try to connect to {$endpoint} and pass: ".print_r($stock, true)); $response = $client->post( 'mock.api.php', [ 'json' => $stock, 'timeout' => 10, 'connect_timeout' => 5, ]); error_log( "Stock#: {$stockNo} sent to $endpoint - Response ({$response->getStatusCode()}): " . $response->getBody() ); } catch (RequestException $e) { error_log( "Error sending to $endpoint: " . ($e->hasResponse() ? $e->getResponse()->getBody()->getContents() : $e->getMessage()) ); } } }endpoint: mock.api.php:
file_put_contents('log.txt', date('c') . " - Start API\n", FILE_APPEND); // Capture the API key from headers $headers = getallheaders(); $apiKey = $headers['apikey'] ?? $headers['Apikey'] ?? null; error_log(print_r($headers,true)); // Check API key if ($apiKey !== 'P9SAa5RJTk9waUJW9gzD') { sendJsonAndExit(403, ['error' => 'Invalid API key']); } // Get request method $method = $_SERVER['REQUEST_METHOD']; if ($method !== 'POST') { sendJsonAndExit(405, ['error' => 'Method Not Allowed']); } // Read the incoming JSON $data = json_decode(file_get_contents('php://input'), true); if (!$data) { sendJsonAndExit(400, ['error' => 'Invalid JSON payload']); } // Log request for debugging (optional) file_put_contents('log.txt', date('Y-m-d H:i:s') . " - " . json_encode($data) . "\n", FILE_APPEND); // Respond with a fake success message sendJsonAndExit(200, [ 'status' => 'success', 'stock_feed_id' => 'AAAA', 'message' => 'Mock API received the data', 'received' => $data ]); function sendJsonAndExit(int $status, array $payload): never { $body = json_encode($payload); http_response_code($status); header('Content-Type: application/json'); header('Connection: close'); header('Content-Length: ' . strlen($body)); echo $body; file_put_contents('log.txt', date('c') . " - End API\n", FILE_APPEND); exit; }error_log:
File Processing Started: 29/01/2026 10:20:59 [29-Jan-2026 10:21:04 Australia/Victoria] Connected to mailbox: 'xxx' [29-Jan-2026 10:21:04 Australia/Victoria] xxx is a valid customer [29-Jan-2026 10:21:04 Australia/Victoria] Dealer validated: xxx|New [29-Jan-2026 10:21:04 Australia/Victoria] About to POST to /mock.api.php for xxx [29-Jan-2026 10:21:14 Australia/Victoria] Error creating stock feed: cURL error 28: Operation timed out after 10009 milliseconds with 0 bytes received (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) [29-Jan-2026 10:21:14 Australia/Victoria] Done processing email#1 [29-Jan-2026 10:21:14 Australia/Victoria] xxx is a valid customer [29-Jan-2026 10:21:14 Australia/Victoria] Dealer validated: xxx|Used [29-Jan-2026 10:21:14 Australia/Victoria] About to POST to /mock.api.php for xxx [29-Jan-2026 10:21:15 Australia/Victoria] Stock Feed ID Created: AAAA (with referenceId: xxx20260129102114) [29-Jan-2026 10:21:15 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:21:25 Australia/Victoria] Error sending to /mock.api.php: cURL error 28: Operation timed out after 10014 milliseconds with 0 bytes received (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) [29-Jan-2026 10:21:25 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:21:25 Australia/Victoria] Stock#: FU32778 sent to /mock.api.php - Response (200): {"status":"success","stock_feed_id":"AAAA","message":"Mock API received the data","received":{"stock_status":"IN-STOCK", ... } [29-Jan-2026 10:21:25 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:21:35 Australia/Victoria] Error sending to /mock.api.php: cURL error 28: Operation timed out after 10004 milliseconds with 0 bytes received (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) [29-Jan-2026 10:21:35 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:21:35 Australia/Victoria] Stock#: FU32845 sent to /mock.api.php - Response (200): {"status":"success","stock_feed_id":"AAAA","message":"Mock API received the data","received":{"stock_status":"IN-STOCK", ... } [29-Jan-2026 10:21:35 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:21:45 Australia/Victoria] Error sending to /mock.api.php: cURL error 28: Operation timed out after 10010 milliseconds with 0 bytes received (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) [29-Jan-2026 10:21:45 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:21:45 Australia/Victoria] Stock#: FU32880 sent to /mock.api.php - Response (200): {"status":"success","stock_feed_id":"AAAA","message":"Mock API received the data","received":{"stock_status":"IN-STOCK", ... } [29-Jan-2026 10:21:45 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:21:55 Australia/Victoria] Error sending to /mock.api.php: cURL error 28: Operation timed out after 10002 milliseconds with 0 bytes received (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) [29-Jan-2026 10:21:55 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:21:55 Australia/Victoria] Stock#: FU32929 sent to /mock.api.php - Response (200): {"status":"success","stock_feed_id":"AAAA","message":"Mock API received the data","received":{"stock_status":"IN-STOCK", ... } [29-Jan-2026 10:21:55 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:22:05 Australia/Victoria] Error sending to /mock.api.php: cURL error 28: Operation timed out after 10002 milliseconds with 0 bytes received (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) [29-Jan-2026 10:22:05 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:22:05 Australia/Victoria] Stock#: FU32952 sent to /mock.api.php - Response (200): {"status":"success","stock_feed_id":"AAAA","message":"Mock API received the data","received":{"stock_status":"IN-STOCK", ... } [29-Jan-2026 10:22:05 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:22:15 Australia/Victoria] Error sending to /mock.api.php: cURL error 28: Operation timed out after 10009 milliseconds with 0 bytes received (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) [29-Jan-2026 10:22:15 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:22:15 Australia/Victoria] Stock#: FU32962 sent to /mock.api.php - Response (200): {"status":"success","stock_feed_id":"AAAA","message":"Mock API received the data","received":{"stock_status":"IN-STOCK", ... } [29-Jan-2026 10:22:15 Australia/Victoria] Lets try to connect to /mock.api.php and pass: Array ( ... ) [29-Jan-2026 10:22:25 Australia/Victoria] Error sending to /mock.api.php: cURL error 28: Operation timed out after 10003 milliseconds with 0 bytes received (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)