もっふもふの電子回路

備忘録的なあれ

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

背景

環境:
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);

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


以上





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

wordpress rss feed 設定メモ

今までrssフィードをページに表示する際にはページのテンプレートに表示処理を書いて、
キャッシュの更新間隔等の設定は「wp-includes\feed.php」内のset_cache_durationを直接変更していた。

これではwordpressを更新した際に変更した設定がデフォルトに戻されるので、
今までは顧客納品時にwordpressの更新はしないでくださいなどと言っていた。
しかし普通に解決方法があったので懺悔がてらメモに記載。

今までやっていた記載。

テンプレートファイル

//WrodPressのfeed.phpの呼び出し
include_once ABSPATH . WPINC . '/feed.php';
// 目的のFeedを取得
$feed = fetch_feed('rssのurl');

//以下 $feed内のメンバ関数にて表示処理

wp-includes\feed.php

function fetch_feed( $url ) {
・
・
・
//$feed->set_cache_duration( apply_filters( 'wp_feed_cache_transient_lifetime', 12 * HOUR_IN_SECONDS, $url ) );
$feed->set_cache_duration( apply_filters( 'wp_feed_cache_transient_lifetime', 30 * MINUTE_IN_SECONDS, $url ) ); //更新間隔を30分ごとに変更
}

解決方法

テンプレートファイル

//WrodPressのfeed.phpの呼び出し
include_once ABSPATH . WPINC . '/feed.php';
// 目的のFeedを取得
$feed = fetch_feed('rssのurl');
$feed ->set_cache_duration(1800);
$feed ->init();

//以下 $feed内のメンバ関数にて表示処理

上記のように普通にインスタンスからset_cache_duration設定できたっぽい。知らなかった。
今まですごい頭悪いことしてたんだな。。。お客様今まで大変申し訳ございませんでした。

以上