0

現在、を使用して基本的なHTTPサーバーをセットアップしており、同じ方法BaseHTTPRequestHandlerを使用しています。リクエストが5秒間届かない場合にdo_GET、関数が呼び出されるようにします。check

マルチプロセッシングとタイムモジュールの併用を検討していますが、信頼性が気になります。同じことに関連するベストプラクティスの提案はありますか?

ありがとう。

[編集]

Marjinのソリューションは本当にクールですが、私は次のトレースバックになります:-

Traceback (most recent call last):
  File "test.py", line 89, in <module>
    main()
  File "test.py", line 83, in main
    server.serve_forever()
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/SocketServer.py", line 224, in serve_forever
    r, w, e = select.select([self], [], [], poll_interval)
select.error: (4, 'Interrupted system call')

[編集2]Python2.7で試しましたが、それでもエラーが発生します。

[編集3]

Traceback (most recent call last):
  File "test.py", line 90, in <module>
    main()
  File "test.py", line 84, in main
    server.serve_forever()
  File "/usr/local/lib/python2.7/SocketServer.py", line 225, in serve_forever
    r, w, e = select.select([self], [], [], poll_interval)
select.error: (4, 'Interrupted system call')
4

1 に答える 1

1

ベースのような単純なサーバーのBaseHTTPRequestHandler場合、シグナルハンドラーを使用できます。

import time
import signal
import sys

last_request = sys.maxint  # arbitrary high value to *not* trigger until there has been 1 requests at least

def itimer_handler(signum, frame):
    print 'itimer heartbeat'
    if time.time() - last_request > 300:  # 5 minutes have passed at least with no request
        # do stuff now to log, kill, restart, etc.
        print 'Timeout, no requests for 5 minutes!'

signal.signal(signal.SIGALRM, itimer_handler) 
signal.setitimer(signal.ITIMER_REAL, 30, 30)  # check for a timeout every 30 seconds

# ...
def do_GET(..):
    global last_request
    last_request = time.time()  # reset the timer again

このsignal.setitimer()呼び出しにより、OS は定期的SIGALRMにシグナルをプロセスに送信します。これはあまり正確ではありません。setitimer)コールは 30 秒間隔に設定されています。受信リクエストはすべてグローバル タイムスタンプをリセットし、itimer_handler30 秒ごとに呼び出される は、最後にタイムスタンプが設定されてから 5 分が経過したかどうかを比較します。

シグナルは実行中のSIGALRMリクエストも中断するため、そのハンドラーで行うことはすべて迅速に終了する必要があります。関数が戻ると、スレッドのように通常の Python コード フローが再開されます。

これが機能するには、少なくとも Python 2.7.4 が必要であることに注意してください。issue 7978を参照してください。2.7.4はまだリリースされていません。SocketServer.pyPython 2.7.4 に含まれるファイルをダウンロードするか、次のバックポートを適用してerrorno.EINTR、そのバージョンで導入された処理を追加できます。

'''Backport of 2.7.4 EINTR handling'''

import errno
import select
import SocketServer


def _eintr_retry(func, *args):
    """restart a system call interrupted by EINTR"""
    while True:
        try:
            return func(*args)
        except (OSError, select.error) as e:
            if e.args[0] != errno.EINTR:
                raise


def serve_forever(self, poll_interval=0.5):
    """Handle one request at a time until shutdown.

    Polls for shutdown every poll_interval seconds. Ignores
    self.timeout. If you need to do periodic tasks, do them in
    another thread.
    """
    self._BaseServer__is_shut_down.clear()
    try:
        while not self._BaseServer__shutdown_request:
            # XXX: Consider using another file descriptor or
            # connecting to the socket to wake this up instead of
            # polling. Polling reduces our responsiveness to a
            # shutdown request and wastes cpu at all other times.
            r, w, e = _eintr_retry(select.select, [self], [], [],
                                   poll_interval)
            if self in r:
                self._handle_request_noblock()
    finally:
        self._BaseServer__shutdown_request = False
        self._BaseServer__is_shut_down.set()


def handle_request(self):
    """Handle one request, possibly blocking.

    Respects self.timeout.
    """
    # Support people who used socket.settimeout() to escape
    # handle_request before self.timeout was available.
    timeout = self.socket.gettimeout()
    if timeout is None:
        timeout = self.timeout
    elif self.timeout is not None:
        timeout = min(timeout, self.timeout)
    fd_sets = _eintr_retry(select.select, [self], [], [], timeout)
    if not fd_sets[0]:
        self.handle_timeout()
        return
    self._handle_request_noblock()


# patch in updated methods
SocketServer.BaseServer.serve_forever = serve_forever
SocketServer.BaseServer.handle_request = handle_request
于 2013-02-11T14:50:04.263 に答える