The curl_multi_* series functions are very important tools when using PHP's cURL extension for concurrent requests. curl_multi_close is responsible for closing a cURL multi handle , but if used improperly, it can easily lead to abnormal connection status, such as: some requests are not completed, resources are not released correctly, and inexplicable timeouts occur. So, how can we avoid these exceptions gracefully and correctly? This article will explain in detail.
When many developers process concurrent requests, the code may look like this:
<?php
$mh = curl_multi_init();
$ch1 = curl_init('https://gitbox.net/api/endpoint1');
$ch2 = curl_init('https://gitbox.net/api/endpoint2');
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// Start and execute
do {
$status = curl_multi_exec($mh, $active);
curl_multi_select($mh);
} while ($active && $status == CURLM_OK);
// Close directly
curl_multi_close($mh);
The problem with this writing method is that even if the request has not been fully processed (especially when the network conditions are poor), curl_multi_close is called directly, which will cause some connections to be terminated roughly, and as a result, a state abnormality will naturally occur.
Before calling curl_multi_close , you should make sure that all handles ( cURL handle ) have been processed and they are removed! The correct process should be:
Curl_multi_exec is called repeatedly until all requests are completed.
Removes each individual cURL handle ( curl_multi_remove_handle ).
Close a single cURL handle ( curl_close ) separately.
Finally, close multi handle ( curl_multi_close ).
The modified code example is as follows:
<?php
$mh = curl_multi_init();
$ch1 = curl_init('https://gitbox.net/api/endpoint1');
$ch2 = curl_init('https://gitbox.net/api/endpoint2');
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// Start and execute
do {
$status = curl_multi_exec($mh, $active);
if ($active) {
curl_multi_select($mh);
}
} while ($active && $status == CURLM_OK);
// Remove and close a single handle
curl_multi_remove_handle($mh, $ch1);
curl_close($ch1);
curl_multi_remove_handle($mh, $ch2);
curl_close($ch2);
// Last Close multi handle
curl_multi_close($mh);
curl_multi_remove_handle must be done before curl_multi_close .
Even if the connection failed to request, it must be cleaned correctly through remove_handle + close .
Using curl_multi_select in a loop can reduce CPU usage and avoid busy waiting.
Try to catch errors (such as curl_errno and curl_error ), and do not blindly trust the request to succeed.
In high concurrency scenarios, details determine success or failure. The essence of curl_multi_close is just to destroy the multi handle, which itself does not and cannot guarantee the secure closing of all single connections. Therefore, before closing the multi handle, be sure to manually remove and close each individual handle , which is the key to avoiding connection status exceptions.
Following the correct processing process can enable your concurrent requests to run stably and efficiently, away from those headache-prone hidden bugs.