Guzzleでタイムアウトを1秒未満に設定したい時に必要となる記述を残しておきます。

前提条件

  • Guzzle 6系
  • PHP 5.6系

解決方法

curlのオプション CURLOPT_NOSIGNALtrue にします。

use GuzzleHttp\Client;

$request_params = ['hoge' => 'foo'];
$guzzle_client = new Client(['base_uri' => 'http://example.com/']);
$http_response = $guzzle_client->request(
    'POST',
    '/api',
    [
        'timeout' => 0.1,  // 100msec
        'curl'    => [CURLOPT_NOSIGNAL => true],   // これが要!
        'json'    => $request_params
    ]
);
var_dump($http_response->getBody());

背景説明

内部的には、Guzzle→PHP→libcurlという流れで実行されています。libcurlは(少なくとも)Linux環境において、ディストリビューションが提供する標準のものを利用すると、タイムアウトはカーネルが提供するシグナル SIGALRM を使います。

しかし、 SIGALRM は秒単位でしか設定できないことが、今回の問題のポイントです。ですので、1秒未満になると切り捨てられてまともに動きません。

そこで、libcurlにてシグナルを使わないよう設定をした上で、タイムアウトを設定すると、シグナルに頼らずタイムアウトを観測できるようになり、問題が解決します。

なお、Guzzleのタイムアウトの設定は CURLOPT_TIMEOUT ではなく CURLOPT_TIMEOUT_MS を使っていて、Guzzleとしては1秒未満の値を定義することはできます。ここ、私が勘違いしていたところでした。

謝辞

@do-aki@github さんに助言いただきました。どうもありがとうございました!

参考文献

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.