Скрипт Python зависает бесконечно во время подключения к сокету - PullRequest
1 голос
/ 11 октября 2011

У меня есть простой скрипт на python, который обновляет статусы потоков justin.tv в моей базе данных.Это веб-приложение на основе Django.Этот скрипт прекрасно работал до того, как я переместил его на свой рабочий сервер, но теперь у него есть проблемы с тайм-аутом или зависанием.Я решил проблему с тайм-аутом, добавив блоки try / кроме и сделав скрипт повторным, но я все еще не могу понять проблему замораживания.Это та же самая точка, где возникает исключение socket.timeout.Однако иногда он просто запирается навсегда.Я просто не могу представить сценарий, в котором питон будет бесконечно зависать.Вот код для скрипта, который зависает.Я связываю сайт website.networkmanagers ниже, а также oauth и используемую мной библиотеку python justin.tv.

import sys, os, socket

LOG = False

def updateStreamInfo():
    # Set necessary paths
    honstreams = os.path.realpath(os.path.dirname(__file__) + "../../../")
    sys.path.append(honstreams)
    os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

    # Import necessary moduels
    from website.models import Stream, StreamInfo
    from website.networkmanagers import get_manager, \
                                        NetworkManagerReturnedErrorException

    # Get all streams
    streams = Stream.objects.all()

    try:
        # Loop through them
        for stream in streams:

            skipstream = False

            print 'Checking %s...' % stream.name,
            # Get the appropriate network manager and
            manager = get_manager(stream.network.name)

            # Try to get stream status up to 3 times
            for i in xrange(3):
                try:
                    streamOnline = manager.getStreamOnline(stream.name, LOG)
                    break
                except socket.error as e:
                    code, message = e

                    # Retry up to 3 times
                    print 'Error: %s. Retrying...'

            # If this stream should be skipped
            if(skipstream):
                print 'Can\'t connect! Skipping %s' % stream.name
                continue

            # Skip if status has not changed
            if streamOnline == stream.online:
                print 'Skipping %s because the status has not changed' % \
                      stream.name
                continue

            # Save status
            stream.online = streamOnline
            stream.save()

            print 'Set %s to %s' % (stream.name, streamOnline)

    except NetworkManagerReturnedErrorException as e:
        print 'Stopped the status update loop:', e

if(__name__ == "__main__"):
    if(len(sys.argv) > 1 and sys.argv[1] == "log"):
        LOG = True

    if(LOG): print "Logging enabled"

    updateStreamInfo()

networkmanagers.py oauth.py JtvClient.py

Пример зависания скрипта

foo @ bar: /.../ honstreams / honstreams # python website / scripts / updateStreamStatus.pyПроверка сердитости ... Пропуск сердитости, потому что статус не изменилсяПроверка chustream ... Пропуск chustream, потому что статус не изменилсяПроверка cilantrogamer ... Пропускание cilantrogamer, потому что статус не изменился|<- карета сидит здесь, мигая бесконечно</p>


Интересное обновление

Каждый раз, когда он зависает и я посылаю прерывание клавиатуры, оно находится на одной и той же строке в socket.py :

root@husta:/home/honstreams/honstreams# python website/scripts/updateStreamStatus.py
Checking angrytestie... Skipping angrytestie because the status has not changed
Checking chustream... Skipping chustream because the status has not changed
^CChecking cilantrogamer...
Traceback (most recent call last):
  File "website/scripts/updateStreamStatus.py", line 64, in <module>
    updateStreamInfo()
  File "website/scripts/updateStreamStatus.py", line 31, in updateStreamInfo
    streamOnline = manager.getStreamOnline(stream.name, LOG)
  File "/home/honstreams/honstreams/website/networkmanagers.py", line 47, in getStreamOnline
    return self.getChannelLive(channelName, log)
  File "/home/honstreams/honstreams/website/networkmanagers.py", line 65, in getChannelLive
    response = client.get('/stream/list.json?channel=%s' % channelName)
  File "/home/honstreams/honstreams/website/JtvClient.py", line 51, in get
    return self._send_request(request, token)
  File "/home/honstreams/honstreams/website/JtvClient.py", line 90, in _send_request
    return conn.getresponse()
  File "/usr/lib/python2.6/httplib.py", line 986, in getresponse
    response.begin()
  File "/usr/lib/python2.6/httplib.py", line 391, in begin
    version, status, reason = self._read_status()
  File "/usr/lib/python2.6/httplib.py", line 349, in _read_status
    line = self.fp.readline()
  File "/usr/lib/python2.6/socket.py", line 397, in readline
    data = recv(1)
KeyboardInterrupt

Есть мысли?

Ответы [ 3 ]

0 голосов
/ 12 октября 2011

Вы пытались использовать другое приложение, чтобы открыть это соединение? Учитывая, что это проблема в работе, возможно, у вас нет проблем с брандмауэром.

0 голосов
/ 03 ноября 2011

Оказывается, это HTTP-соединение не прошло тайм-аут в jtvClient.py

def _get_conn(self):
    return httplib.HTTPConnection("%s:%d" % (self.host, self.port))

Изменена последняя строка на

return httplib.HTTPConnection("%s:%d" % (self.host, self.port), timeout=10)

Который решил это

0 голосов
/ 12 октября 2011

Внизу в JtvClient.py он использует httplib для обработки соединения.Вы пытались изменить это, чтобы вместо этого использовать httplib2?

Кроме этого удара в темноте, я бы добавил в этот код множество операторов регистрации, чтобы отслеживать, что на самом деле происходит и где он застревает.Тогда я бы позаботился о том, чтобы точка, в которой он застрял, могла выдержать таймаут в сокете (который обычно включает в себя либо monkeypatching, либо разветвление кодовой базы), так что вещи перестали зависать, а не зависали.*

Я знаю, что он зависает на линии streamOnline = manager.getStreamOnline (stream.name, LOG).Это та же самая точка, где возникает исключение socket.timeout.

Неверно.Он не останавливается на этой строке, потому что эта строка является вызовом функции, которая вызывает множество других функций через несколько уровней других модулей.Таким образом, вы еще не знаете, где программа зависает.Кроме того, эта строка является NOT точкой, где происходит таймаут сокета.Тайм-аут сокета будет происходить только в низкоуровневой операции сокета, такой как select или recv, которая вызывается несколько раз в цепочке действий, запускаемой getStreamOnline.

Вам необходимо отследить код в отладчике или добавить операторы печатичтобы отследить, где именно происходит зависание.Это может быть бесконечный цикл в Python, но скорее всего это низкоуровневый вызов сетевой функции ОС.Пока вы не найдете источник ошибки, вы ничего не сможете сделать.

PS Прерывание клавиатуры - разумный признак того, что проблема в строке 90 в JtvClient.py, поэтому вставьте несколько операторов print и найдитеиз того, что происходит.Там может быть тупой цикл, который продолжает вызывать getresponse, или вы можете вызывать его с неверными параметрами, или, возможно, сетевой сервер действительно перегружен.Сузьте это до меньшего количества возможностей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...