【问题标题】:Infinite running server-side python script?无限运行服务器端 python 脚本?
【发布时间】:2016-06-09 09:29:47
【问题描述】:

我想替换 Cron Jobs 以“保持”我的程序处于活动状态,因为无论脚本是否已被调用,它都会每隔 XX 间隔调用一次,从而创建重复的条目。

我调查了这个问题,并有一些方法。一种是修改我的程序,以便检查它是否已被调用并自行关闭。我追求的是通过使用execfile 一遍又一遍地调用自己来将它与 Cronjob 完全分离,这完全符合我的要求,除了以下问题: RuntimeError: maximum recursion depth exceeded

有没有办法让程序保持“无限循环”而不会出现堆栈溢出?

这是我的代码,它是一个检查邮件并将其转换为 MySQL 数据库条目的程序。

imap = imaplib.IMAP4(hst)

try:
   imap.login(usr, pwd)
except Exception as e:
   errormsg = e
   time.sleep(30)
   print "IMAP error: " + str(errormsg)
   execfile('/var/www/html/olotool/converter.py')
   raise IOError(e)


# Authentification & Fetch Step

while True:

    time.sleep(5)
    '''
    The script will always result in an error if there
    are no mails left to check in the inbox. It then
    goes into sleep mode and relaunches itself to check
    if new mails have arrived.
    '''
    try:
        imap.select("Inbox") # Tell Imap where to go
        result, data = imap.uid('search', None, "ALL")
        latest = data[0].split()[-1]
        result, data = imap.uid('fetch', latest, '(RFC822)')
        raw = data[0][1] # This contains the Mail Data
        msg = email.message_from_string(raw)

    except Exception as e:
        disconnect(imap)
        time.sleep(60)
        execfile('/var/www/html/olotool/converter.py')
        raise IOError(e)

【问题讨论】:

  • 我不明白你为什么在没有邮件的情况下引发异常,然后重新启动脚本。为什么不只检查新电子邮件,然后仅在resultdata 不为空时处理邮件?如果您希望它永远运行,一个简单的while True 对可能的数据结果进行错误检查就足够了。如果你想要某种脚本管理,你可以使用 supervisord 来确保你的脚本正在运行,并在它碰巧因意外错误而崩溃时重新启动。
  • 不能只检查新邮件,因为人们正在使用该收件箱,我每天收到大约 20 多封不同类型的邮件 +/- 2000 封邮件,如果是的话,我必须检查每封邮件我必须处理的东西。上面的脚本只是一小部分,脚本如何开始以及完成后应该如何结束。基本上,我必须检查一大堆东西,然后将条目写入 MySQLdb。我知道我的做法很糟糕,但我必须从某个地方开始。

标签: python python-2.7 loops recursion rhel


【解决方案1】:

我现在用我认为可能的唯一方法自己解决了这个问题。 首先我在上面的代码中改变了我的异常:

except Exception as e:
    disconnect(imap)
    print "Converter: No messages left"
    raise os._exit(0) 
    # This is a special case since this Exception is
    # no error thus os._exit(0) gives no false-positives

如您所见,我现在避免使用execfile。相反,我编写了一个控制器脚本来检查我的 converter.py 的状态并在它尚未运行时启动它:

while True:

    presL = os.popen('pgrep -lf python').read()
    print "________________________________________"
    print "Starting PIDcheck"
    print "Current Processes: " 
    print presL # Check Processes

    presRconverter = find('\d{7} python converter.py', presL)
    if presRconverter:
        # Store the PID
        convPID = find('\d{7}', presRconverter)
        print "Converter is running at PID: " + convPID

    else:
        print "PID Controller: Converter not running"
        try:
            print "PID Controller: Calling converter"
            subprocess.check_call('python converter.py', shell=True)

        except subprocess.CalledProcessError as e:
            errormsg = e
            print "Couldn't call Converter Module"
            sendMail(esender,ereceiver,esubject,etext,server)
            print "Error notification send"
            raise IOError(e)

    # If we got until here without ERROR, the call was Successfull
    print "PID Controller: Call successful"
    print "________________________________________"
    time.sleep(60)

此方法不会引发:RuntimeError: maximum recursion depth exceeded。如果您使用命令nohup python converter.py 运行控制器,这还会为您提供nohup.out 文件,您可以在其中看到错误处理的任何问题。

我希望我可以帮助遇到同样问题的人。

【讨论】:

    【解决方案2】:

    类似这样的东西应该可以工作,而不必求助于子进程检查等:

    def check_mail_loop():
        imap = imaplib.IMAP4(hst)
        # Build some function to login, and, in the event of an error, sleep for n seconds and call login function again.
        imap.login(usr, pwd)
    
        while True:
            try:
                imap.select("Inbox")
                result, data = imap.uid('search', None, "ALL")
    
                if result and data:
                    latest = data[0].split()[-1]
                    result, data = imap.uid('fetch', latest, '(RFC822)')
                    raw = data[0][1] # This contains the Mail Data
                    msg = email.message_from_string(raw)
                time.sleep(5)
            except SomeRelevantException as e:
                logging.log(e)
                time.sleep(60)
                pass
    

    如果出现您没有预见到的随机错误,请使用流程控制管理器,例如 supervisord 或 monit。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-26
      • 1970-01-01
      • 1970-01-01
      • 2016-07-22
      • 1970-01-01
      相关资源
      最近更新 更多