ヒトリ歩き

愚痴とかいろいろ書きます

デコレータでタイムアウトを設定しよう!!

時間がかかる処理に対して、タイムアウトを設定したい場合に使用するためのデコレータとして、timeout_decorator.timeoutがあるので、使ってみた。 用途として、サーバに対する検索のリクエストを実行した際に、検索に時間がかかる場合にタイムアウトを設定する。

github.com

timeout_decorator.timeoutデコレータのパラメータに関数がコールされてからタイムアウトする 秒数を指定。 下記の例の場合、10秒スリープする処理を入れているが、デコレータに5秒でタイムアウトするように設定している。 5秒が経過すると、timeout_decorator.timeout_decorator.TimeoutErrorが発生する。

import time
import timeout_decorator

# 5秒後にタイムアウトする
@timeout_decorator.timeout(5)
def call_func():
    print("Start call_func")
    time.sleep(10)
    print("End call_func")

if __name__ == '__main__':
    i = 0
    while i < 3:
        call_func()
        i += 1

独自のエラーをライズしたい

timeout_decorator.timeout_decorator.TimeoutErrorではなく、独自で定義した Exceptionクラスをレイズしたい場合、timeout_exceptionパラメータにレイズしたい Exceptionクラスを指定することで可能。

下記の例だと、timeout_exceptionパラメータにNewErrorクラスを指定。 タイムアウトが発生すると、NewErrorクラスがレイズされる。

import time
import timeout_decorator

class NewError(Exception):
    pass

# 5秒後にタイムアウトする
@timeout_decorator.timeout(5, timeout_exception=NewError)
def call_func():
    print("Start call_func")
    time.sleep(10)
    print("End call_func")

if __name__ == '__main__':
    i = 0
    while i < 3:
        call_func()
        i += 1

時間がかかる検索にはタイムアウトを設定しよう

HTTPリクエストで時間がかかる処理をタイムアウトするために、timeout_decorator.timeoutデコレータを 使ってタイムアウトを設定しよう。 ただ、requestsモジュールにはタイムアウトの機能が存在するので、requestsモジュールを使用する場合は、 requestsモジュールのタイムアウト機能を素直に使いましょう。

import timeout_decorator
import requests

@timeout_decorator.timeout(10)
def call_func():

    print("Send Request!!")
    response = requests.get("http://localhost:8000"params=None)
    print("Receive Response!!")

if __name__ == '__main__':
    i = 0
    while i < 3:
        call_func()
        i += 1

requests.readthedocs.io

最後に

モジュールをインストールして、デコレータの設定のみでタイムアウト機能が実装できた。 他にもタイムアウトを実装したモジュールがあるようなので、用途によって使い分けたほうがいいかと思う。

scrapbox.io