Current Location: Home> Latest Articles> How to implement timeout control of requests in curl_multi_close

How to implement timeout control of requests in curl_multi_close

gitbox 2025-05-12

In PHP, the curl_multi_* series of functions allow you to send multiple HTTP requests concurrently, greatly improving the execution efficiency of the program. However, when many people use curl_multi_close to end multi-request sessions, they tend to ignore an important issue:

If the timeout time is not reasonably controlled, when a request is unresponsive for a long time, the entire application may be stuck, resulting in a very bad user experience. This article will use examples to teach you how to elegantly implement timeout control when using curl_multi_close .

Basic ideas

In fact, curl_multi_close is only used to close the curl_multi handle, and it does not control the timeout itself. The real timeout control should occur at the stage of executing the request (i.e. curl_multi_exec and curl_multi_select ).

Simply put, timeout control depends on:

  • Set timeout on a single curl handle

  • Record and judge the total time in the execution loop

Sample code

Here is a practical example. Suppose we have two requests, requesting https://gitbox.net/api/endpoint1 and https://gitbox.net/api/endpoint2 , we hope that all requests will not take more than 10 seconds in total.

 <?php

// Create two cURL Handle
$ch1 = curl_init('https://gitbox.net/api/endpoint1');
$ch2 = curl_init('https://gitbox.net/api/endpoint2');

// Set a timeout for each request separately(Optional)
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch1, CURLOPT_TIMEOUT, 8); // The most requests per person8Second
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_TIMEOUT, 8);

// Create a cURL 批处理Handle
$mh = curl_multi_init();

// 添加Handle到批处理Handle中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);

// Perform batch processing
$startTime = microtime(true);
$timeout = 10; // Total timeout(Second)

do {
    $status = curl_multi_exec($mh, $active);

    // If there is still an active connection
    if ($active) {
        // Blocking and waiting
        $n = curl_multi_select($mh, 1.0);

        // if select return -1,Avoid busy waiting
        if ($n === -1) {
            usleep(100000); // sleep100毫Second
        }
    }

    // Check if timeout
    if ((microtime(true) - $startTime) > $timeout) {
        echo "The total time to request exceeds{$timeout}Second,Forced interruption。\n";
        break;
    }
} while ($active && $status == CURLM_OK);

// Read the result
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);

// 关闭Handle
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);
curl_close($ch1);
curl_close($ch2);

// Print results
echo "Response 1: " . substr($response1, 0, 100) . "...\n";
echo "Response 2: " . substr($response2, 0, 100) . "...\n";
?>

Summary of key points

  1. CURLOPT_TIMEOUT controls the timeout of a single request ;

  2. By recording microtime(true) , the total execution time is manually controlled;

  3. When using curl_multi_select , set an appropriate timeout value (such as 1 second) to avoid excessive CPU usage;

  4. curl_multi_close is only responsible for cleaning resources and does not control any timeout logic .

Things to note

  • If you set a too short select timeout (for example, 0.01 seconds), the system load may increase.

  • If curl_multi_select returns -1, it means there is no file descriptor to wait and requires proper sleep ( usleep ) to avoid busy loops.

  • When a timeout occurs, it is best to proactively cancel the unfinished request to avoid resource leakage.