読者です 読者をやめる 読者になる 読者になる

もっふもふの電子回路

備忘録的なあれ

Twitter APIで連打でリクエスト投げたときの話

PHP WordPress Twitter API TwistOAuth

背景

環境:
wordpress
・x-server
・PHP5.6.22くらい
・ライブラリ TwistOAuth(非phar)

Twitter APIにてsearchリクエストを連打で投げる必要がある案件にあたったけど、リクエスト上限(180req/15min)にすぐ引っかかるような要求仕様だったので苦労した話

TwistOAuth

すげーいい。これがあればすぐプログラム組める。使いやすい。
でもリクエスト上限に達した場合に例外吐くだけなのでリスポーン処理が組みづらい。

対策

TwistOAuth内のTwistOAuth.phpでgetリクエストする際のcurlのオプションと、関数decodeを修正した。

public function get
public function get($url, $params = array(), $proxy = '') {
    $ch = $this->curlGet($url, $params, $proxy);
    curl_setopt($ch, CURLOPT_HEADER, true);//--追記
    $response = curl_exec($ch);
    return self::decode($ch, $response);
}
private static function decode
private static function decode($ch, $response) {
    self::checkCurlError($ch);
    $info = curl_getinfo($ch);
    $header = substr ($response, 0, $info["header_size"]);//--追記
    $body = substr ($response, $info["header_size"]);//--追記
    $response = $body;//--追記

||途中省略||

$limitRemain = -1;//残りリクエスト可能回数
$limitReset = -1;//リクエスト回数復活時間unixtime
$headerArr = explode("\n", $header);
$headerArr = array_map('trim', $headerArr);
foreach($headerArr as $headerRow){
    $headerRowData = explode(":", $headerRow);
    if(is_array($headerRowData) && count($headerRowData)==2){
        if($headerRowData[0]=="x-rate-limit-remaining"){
            //echo "x-rate-limit-remaining --- ".$headerRowData[1]."<BR>";
	    if(is_numeric($headerRowData[1])){
	        $limitRemain = intval($headerRowData[1],10);
            }
        }else if($headerRowData[0]=="x-rate-limit-reset"){
            //echo "x-rate-limit-reset --- ".$headerRowData[1]."<BR>";
            if(is_numeric($headerRowData[1])){
                $limitReset = intval($headerRowData[1],10);
            }
        }
    }
}
if($limitRemain!=-1 && $limitRemain===0 && $limitReset!=-1){
    $nowTime = time();
    $waittime = $limitReset-time()+60;
    if($waittime&lt;=0){$waittime=960;}
    update_option('waittime', $waittime);
}else{
    update_option('waittime', 0);
}
return $obj;

function getにレスポンスヘッダを返すためにCURLOPT_HEADERをtrueに。
function decodeの頭でヘッダとレスポンスbodyを分離。
function decodeで正常パターンだった場合のreturn $obj前に残りリクエスト回数解析処理を追加。

意図としては、
Twitter APIでは現在のリクエスト可能回数を取得するエンドポイントがあるが、いちいち確認してたら無駄にリソースを食ってしまう。
そこで、get時に返ってくるレスポンスヘッダを見るようにし、レスポンスヘッダ内の値
・x-rate-limit-remaining (残りリクエスト可能回数)
・x-rate-limit-reset (リクエスト可能回数リセット時間:unixtime)
を毎回確認するようにした。

$waittime = $limitReset-time()+60;
にてリセットされる時刻-現在時刻にて待ち時間を作成。+60は気分で入れた。

環境はwordpressなので、サイトオプションに"waittime"を作成。残りリクエスト可能回数が0以下だった場合に
update_option('waittime', $waittime)
にて次回復活時間をオプションに登録、プログラム上位にてこの値を確認するようにした。


上位でこの"waittime"を都度確認して、0以外だったら

wp_clear_scheduled_hook( 'イベントフック名' );
wp_schedule_event( time()+$waittime, '時間設定名', 'イベントフック名' );
update_option('waittime', 0);

とかやればいい感じにリクエスト回数復活まで待ってくれるはず。
コードが雑なのは勘弁してください。


以上





(はてぶコード内で<をエスケープするにはどうすればええんや...)