🐍

python-twitter-v2を使用するときは、timeoutを設定した方が良いという話

2023/03/19に公開

python-twitter-v2とは

https://github.com/sns-sdks/python-twitter
pythonでTwitter API V2を叩くためのラッパーです。

zsh
pip install python-twitter-v2

でインストールできます。

main.py
from pytwitter import Api
api = Api(
    consumer_key = 'consumer_key',
    consumer_secret = 'consumer_secret',
    access_token = 'access_token',
    access_secret = 'access_secret'
)
try:
    api.create_tweet(text = 'Hello World')
except:
    print('Twitter投稿エラー')

と、シンプルなコードでTwitter API V2経由のツイートが実現出来て便利です。

何が起きたか?

定時実行しているプログラムが、何もエラーを吐かずに動作を停止していました。
前項の例のようにtry-exceptcreate_tweet失敗時にcatchするようにしているのですが、ログを調査するとどうもcreate_tweet実行後の処理を通っていない模様。
実行時刻は2023/03/18 15:29頃。

SNSで検索してみると、どうも当該時刻前後でTwitterがダウンしていたらしいです。
https://twitter.com/DowndetectorJP/status/1636979125251448833?s=20

プログラムの挙動とTwitterの障害情報を見る限り、requestしてもresponseが返らず、ずっと待機していたように見えます。

python-twitterの処理を追う

https://github.com/sns-sdks/python-twitter/blob/c7f2162cdab3a2a6ea5ac8d2b76756125662dd8e/pytwitter/api.py#L163

python-twitter/pytwitter/api.py
        resp = self.session.request(
            url=url,
            method=verb,
            params=params,
            data=data,
            auth=auth,
            json=json,
            timeout=self.timeout,
            proxies=self.proxies,
        )

RequestsのSessionからrequestをしていて、timeoutself.timeoutの値が使用されています。

https://github.com/sns-sdks/python-twitter/blob/c7f2162cdab3a2a6ea5ac8d2b76756125662dd8e/pytwitter/api.py#L50

python-twitter/pytwitter/api.py
    def __init__(
        self,
        bearer_token: Optional[str] = None,
        consumer_key: Optional[str] = None,
        consumer_secret: Optional[str] = None,
        access_token: Optional[str] = None,
        access_secret: Optional[str] = None,
        client_id: Optional[str] = None,
        client_secret: Optional[str] = None,
        application_only_auth: bool = False,
        oauth_flow: bool = False,  # provide access with authorize
        sleep_on_rate_limit: bool = False,
        timeout: Optional[int] = None,
        proxies: Optional[dict] = None,
        callback_uri: Optional[str] = None,
        scopes: Optional[List[str]] = None,
    ) -> None:
        self.session = requests.Session()
        self._auth = None
        self._oauth_session = None
        self.consumer_key = consumer_key
        self.consumer_secret = consumer_secret
        self.client_id = client_id
        self.client_secret = client_secret
        self.timeout = timeout

コンストラクタでself.timeoutが設定されているのですが、初期値がNoneになっていました。

Requestsのtimeout

https://docs.python-requests.org/en/latest/user/advanced/#timeouts
Requestsのドキュメントによると、timeoutは設定すべきとされています。

timeoutにはconnect(サーバとの接続の確立)とread(サーバからresponseが返ってくる)の二種類があり、

  • 両方に同じ値を設定する方法
    r = requests.get('https://github.com', timeout=5)
    
  • それぞれにタプルで値を設定する方法
    r = requests.get('https://github.com', timeout=(3.05, 27))
    

の二通りの書き方があります。

python-twitter-v2のtimeout

python-twitter-v2のコンストラクタで設定されるself.timeoutの値がそのままRequestsで使用されているので、floatかタプルで設定できそうに見えますが、コンストラクタを見ると

python-twitter/pytwitter/api.py
timeout: Optional[int] = None,

と、intが要求されているので、念のためintで値を設定してあげるとよいかと思われます。

main.py
api = Api(
    consumer_key = 'consumer_key',
    consumer_secret = 'consumer_secret',
    access_token = 'access_token',
    access_secret = 'access_secret',
    timeout = 30
)

これで、create_tweetなどでTwitterへrequestを送る際、タイムアウトしたらexceptで拾えるようになります。

まとめ

Twitterが落ちたらプログラムが止まるので、python-twitter-v2を使用する際はtimeoutを設定しておきましょう。

Discussion