AWS Elastic Beanstalk - 脚本在返回标头之前超时:application.py

Posted

技术标签:

【中文标题】AWS Elastic Beanstalk - 脚本在返回标头之前超时:application.py【英文标题】:AWS Elastic Beanstalk - Script timed out before returning headers: application.py 【发布时间】:2017-06-08 07:49:03 【问题描述】:

我在 AWS 上有一个现有的 Elastic Beanstalk 烧瓶应用程序,它偶尔不会初始化并给出以下错误:

[Mon Jan 23 10:06:51.550205 2017] [core:error] [pid 7331] [client  127.0.0.1:43790] script timed out before returning headers: application.py
[Mon Jan 23 10:10:43.910014 2017] [core:error] [pid 7329] [client 127.0.0.1:43782] End of script output before headers: application.py

任何想法为什么会这样?最近我将项目的requirements.txt 更改为包含pandas==0.19.2。在此更改之前,该程序将运行几天,然后返回相同的错误。更多日志/程序详情:

[Mon Jan 23 10:05:36.877664 2017] [suexec:notice] [pid 7323] AH01232: suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)
[Mon Jan 23 10:05:36.886151 2017] [so:warn] [pid 7323] AH01574: module wsgi_module is already loaded, skipping
AH00557: httpd: apr_sockaddr_info_get() failed for ip-10-55-254-33
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1. Set the 'ServerName' directive globally to suppress this message
[Mon Jan 23 10:05:36.887302 2017] [auth_digest:notice] [pid 7323] AH01757: generating secret for digest authentication ...
[Mon Jan 23 10:05:36.887797 2017] [lbmethod_heartbeat:notice] [pid 7323] AH02282: No slotmem from mod_heartmonitor
[Mon Jan 23 10:05:36.887828 2017] [:warn] [pid 7323] mod_wsgi: Compiled for Python/2.7.10.
[Mon Jan 23 10:05:36.887832 2017] [:warn] [pid 7323] mod_wsgi: Runtime using Python/2.7.12.
[Mon Jan 23 10:05:36.889729 2017] [mpm_prefork:notice] [pid 7323] AH00163: Apache/2.4.23 (Amazon) mod_wsgi/3.5 Python/2.7.12 configured -- resuming normal operations
[Mon Jan 23 10:05:36.889744 2017] [core:notice] [pid 7323] AH00094: Command line: '/usr/sbin/httpd -D FOREGROUND'
[Mon Jan 23 10:06:43.542607 2017] [core:error] [pid 7328] [client 127.0.0.1:43786] Script timed out before returning headers: application.py
[Mon Jan 23 10:06:47.548360 2017] [core:error] [pid 7330] [client 127.0.0.1:43788] Script timed out before returning headers: application.py
[Mon Jan 23 10:06:51.550205 2017] [core:error] [pid 7331] [client 127.0.0.1:43790] Script timed out before returning headers: application.py
[Mon Jan 23 10:10:43.910014 2017] [core:error] [pid 7329] [client 127.0.0.1:43782] End of script output before headers: application.py

应用程序.py

import flask
from flask import request, Response
import logging
import json
import JobType1
import JobType2
import sys


application = flask.Flask(__name__)
application.config.from_object('default_config')
application.debug = application.config['FLASK_DEBUG'] in ['true', 'True']`

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


@application.route('/', methods=['GET'])
def index():
  logger.info("The message received was '/', no action taken")
  response = Response("Success", status=200)
  return response


@application.route('/StartJob', methods=['POST'])
def StartJob():
  logger.info("!!start_job message received! This is the start job logger")
  print("!!start_job message received! This is the start job printer")
  response = None

if request.json is None:
    response = Response("Error, no job specified.", status=400)
else:
    message = dict()

    try:
        if request.json.has_key('TopicArn') and request.json.has_key('Message'):
            message = json.loads(request.json['Message'])
            job = message['job']
        else:
            message = request.json
            job = message['job']
        date_key = None
        try:
            date_key = message['runkey']
        except Exception as e:
            print "printing Exception:"
            print e
            pass
        start_job(job, date_key)
        response = Response("Called Job", status=200)
    except Exception as ex:
        logging.exception("There was an error processing this message: %s" % request.json)
        response = Response("Error processing message", status=400)
return response


@application.route('/CronMessage', methods=['POST'])
def cron_message():
  logger.info("!!Cron message received! This is the Cron Start Logger")
  response = None
  logger.info("About to print headers of CRON***")
  job = request.headers.get('X-Aws-Sqsd-Taskname')
  start_job(job, None)
  response = Response("Called Job", status=200)
  return response


def start_job(job_name, date_key):
  logger.info("JOB NAME SUBMITTED IS:")
  logger.info(job_name)
  if job_name == 'JobType1':
      start_job_if_not_running(job_name, JobType1.main, True, date_key)
  if job_name == 'JobType2':
    start_job_if_not_running(job_name, JobType2.main, True, date_key)
  else:
    print "Submitted job nome is invalid, no job started. The invalid submitted job name was %s" % job_name


def start_job_if_not_running(job_name, program_to_execute, uses_date_key_flag, date_key):
  global running_jobs
  logger.info("running_jobs are:")
  logger.info(running_jobs)

  if job_name in running_jobs:
    logger.info("Currently running job " + job_name + ", will not start again.")
    return False
else:
    try:
        running_jobs.append(job_name)
        if uses_date_key_flag:
            logger.info("")
            program_to_execute(date_key)
        else:
            program_to_execute()
    except Exception as e:
        handle_job_end(job_name)
        print "Error in " + job_name
        error_message = str(e) + "-" + str(sys.exc_info()[0])
        print error_message
        EmailUsers.main(subject="Error in " + job_name,
                        message=error_message,
                        message_type='error',
                        date_key=date_key,
                        job_name=job_name,
                        process_name='application.py',
                        notification_group='bp_only')
    handle_job_end(job_name)


def handle_job_end(job_name):
  while job_name in running_jobs:
    running_jobs.remove(job_name)

logger.info("Process Complete")

if __name__ == '__main__':
  application.run(host='0.0.0.0', threaded=True)

感谢任何帮助,我可以根据需要从其他文件中分享更多代码。

此外,如果我导航到 /etc/httpd/conf.d/wsgi.conf,我会看到:

LoadModule wsgi_module modules/mod_wsgi.so
WSGIPythonHome /opt/python/run/baselinenv
WSGISocketPrefix run/wsgi
WSGIRestrictEmbedded On

<VirtualHost *:80>

Alias /static/ /opt/python/current/app/static/
<Directory /opt/python/current/app/static/>
Order allow,deny
Allow from all
</Directory>


WSGIScriptAlias / /opt/python/current/app/application.py


<Directory /opt/python/current/app/>
  Require all granted
</Directory>

WSGIDaemonProcess wsgi processes=1 threads=15 display-name=%GROUP \
  python-path=/opt/python/current/app:/opt/python/run/venv/lib64/python2.7/site-packages:/opt/python/run/venv/lib/python2.7/site-packages user=wsgi group=wsgi \
  home=/opt/python/current/app
WSGIProcessGroup wsgi
</VirtualHost>

LogFormat "%h (%X-Forwarded-Fori) %l %u %t \"%r\" %>s %b \"%Refereri\" \"%User-Agenti\"" combined

【问题讨论】:

Apache 的 mod_wsgi 配置是什么?当使用numpypandas 等时,您必须强制使用主要的 Python 解释器上下文,否则您会看到该问题。见modwsgi.readthedocs.io/en/develop/user-guides/… @GrahamDumpleton 我已将/etc/httpd/conf.d/wsgi.conf 的内容添加到原始问题中。这有帮助吗?对不起,我的经验不足。 根据链接需要添加WSGIApplicationGroup %GLOBAL% @user2752159 这是否解决了您的问题?我遇到了同样的问题。谢谢。 @GrahamDumpleton 谢谢。我想知道解决方案是否仍然有效。我在我的工作项目中包含了相同的文件,但我仍然收到超时错误。 【参考方案1】:

非常感谢@GrahamDumpleton 的帮助。我使用的解决方案是:

-编辑 Elastic Beanstalk EC2 实例上位于 /etc/httpd/conf.d/wsgi.conf 的 wsgi.conf 文件。

为此,我使用命令 sudo -e /etc/httpd/conf.d/wsgi.conf 打开编辑器,点击 INSERT 开始编辑,并在文件中的任意位置添加 WSGIApplicationGroup %GLOBAL。我然后他的 ESCAPE 并使用命令 :wq 来保存更改。

之后,我从 Elastic Beanstalk 控制台的操作下拉菜单中选择了重新启动应用程序服务器。在此之后,程序将加载并给出 AH00094: Command line: '/usr/sbin/httpd -D FOREGROUND' 消息,但不是之后的错误消息。此外,应用程序将接收 SQS 消息并按预期运行。

需要注意的一点是,如果对 Elastic Beanstalk 配置进行任何配置更改,wsgi.conf 文件似乎将恢复。我不确定解决这个问题的方法,但如果我找到了一些东西,我会在这里发布。

再次感谢@GrahamDumpleton 的及时回复和帮助解决这个问题!

【讨论】:

【参考方案2】:

@user2752159 的回答突出了这个问题,但是我将添加它以展示如何在 AWS Beanstalk 的上下文中克服这个问题(即,如果一个新实例或您部署更多代码,那么问题将保持固定,而不是而不是每次修改wsgi.conf都必须ssh进入盒子。

创建文件。 (注意它以 *.config 而不是 conf 结尾)

nano .ebextensions/<some_name>.config 

将以下内容添加到some_name.config (mod_wsgi docs)

files:
  "/etc/httpd/conf.d/wsgi_custom.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      WSGIApplicationGroup %GLOBAL

添加到 git

git add .ebextensions/<some_name>.config
git commit -m 'message here'

部署到豆茎

eb deploy

现在每次部署时,WSGIApplicationGroup %GLOBAL 都会添加到 wsgi_custom.conf,从而解决问题。

【讨论】:

找到这个问题/答案花了我一段时间,但解决了我的问题 - 非常感谢! @DavidViktora WSGIApplicationGroup %GLOBAL 实际上是如何工作的?我已经阅读了文档,但仍然不太明白。全局应用程序组中的任何 WSGI 应用程序将始终在 Python 初始化时创建的第一个解释器的上下文中执行,即处理请求的进程。 modwsgi.readthedocs.io/en/develop/configuration-directives/… 我将此添加到我的项目中,但仍然收到脚本超时错误。 记得在操作时注意名称:.ebextensions/.CONFIG 我被这个卡住了好几个小时...... 用 Flask Server 解决了我使用 EBS Python 3.6 的问题。谢谢。

以上是关于AWS Elastic Beanstalk - 脚本在返回标头之前超时:application.py的主要内容,如果未能解决你的问题,请参考以下文章

AWS Elastic Beanstalk CLI 安装错误

text AWS Elastic Beanstalk

HTTPS Elastic Beanstalk (AWS) 到 Android

AWS Elastic Beanstalk 无法担任角色

AWS Elastic Beanstalk

AWS Elastic Beanstalk chown PythonPath 错误