部署到 Heroku 时,如何在 Procfile 中导入带有 Gunicorn 的自定义模块?

Posted

技术标签:

【中文标题】部署到 Heroku 时,如何在 Procfile 中导入带有 Gunicorn 的自定义模块?【英文标题】:How do you import a custom module with Gunicorn in a Procfile when deploying to Heroku? 【发布时间】:2016-07-02 20:30:45 【问题描述】:

现在我正在向 Heroku 部署一个 Flask 应用程序,这是一个自定义表单模块。

当我检查 heroku 日志时,它会在尝试导入注册表单时收到导入错误。

2016-03-16T18:40:08.254753+00:00 heroku[web.1]: State changed from crashed to starting
2016-03-16T18:40:12.022731+00:00 heroku[web.1]: Starting process with command `gunicorn app.register:app`
2016-03-16T18:40:14.912795+00:00 app[web.1]: [2016-03-16 18:40:14 +0000] [3] [INFO] Starting gunicorn 19.4.5
2016-03-16T18:40:14.913529+00:00 app[web.1]: [2016-03-16 18:40:14 +0000] [3] [INFO] Listening at: http://0.0.0.0:39309 (3)
2016-03-16T18:40:14.913654+00:00 app[web.1]: [2016-03-16 18:40:14 +0000] [3] [INFO] Using worker: sync
2016-03-16T18:40:14.917468+00:00 app[web.1]: [2016-03-16 18:40:14 +0000] [7] [INFO] Booting worker with pid: 7
2016-03-16T18:40:14.951783+00:00 app[web.1]: [2016-03-16 18:40:14 +0000] [8] [INFO] Booting worker with pid: 8
2016-03-16T18:40:15.665966+00:00 heroku[web.1]: State changed from starting to up
2016-03-16T18:40:15.568052+00:00 app[web.1]: [2016-03-16 18:40:15 +0000] [8] [ERROR] Exception in worker process:
2016-03-16T18:40:15.568074+00:00 app[web.1]: Traceback (most recent call last):
2016-03-16T18:40:15.568076+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/gunicorn/arbiter.py", line 515, in spawn_worker
2016-03-16T18:40:15.568076+00:00 app[web.1]:     worker.init_process()
2016-03-16T18:40:15.568077+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/gunicorn/workers/base.py", line 122, in init_process
2016-03-16T18:40:15.568078+00:00 app[web.1]:     self.load_wsgi()
2016-03-16T18:40:15.568078+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/gunicorn/workers/base.py", line 130, in load_wsgi
2016-03-16T18:40:15.568079+00:00 app[web.1]:     self.wsgi = self.app.wsgi()
2016-03-16T18:40:15.568080+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/gunicorn/app/base.py", line 67, in wsgi
2016-03-16T18:40:15.568081+00:00 app[web.1]:     self.callable = self.load()
2016-03-16T18:40:15.568081+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/gunicorn/app/wsgiapp.py", line 65, in load
2016-03-16T18:40:15.568082+00:00 app[web.1]:     return self.load_wsgiapp()
2016-03-16T18:40:15.568083+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/gunicorn/app/wsgiapp.py", line 52, in load_wsgiapp
2016-03-16T18:40:15.568083+00:00 app[web.1]:     return util.import_app(self.app_uri)
2016-03-16T18:40:15.568084+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/gunicorn/util.py", line 357, in import_app
2016-03-16T18:40:15.568085+00:00 app[web.1]:     __import__(module)
2016-03-16T18:40:15.568086+00:00 app[web.1]:     from registration_form import RegistrationForm
2016-03-16T18:40:15.568086+00:00 app[web.1]:   File "/app/app/register.py", line 2, in <module>
2016-03-16T18:40:15.568087+00:00 app[web.1]: ImportError: No module named 'registration_form'

这就是目录的样子。

app
├── register.py
├── registration_form.py
Procfile
requirements.txt
runtime.txt
virtual

这在我的 Procfile 中。

web: gunicorn app.register:app

这是我的 app/register.py 文件

from flask import Flask, render_template, request
from registration_form import RegistrationForm

app = Flask(__name__)

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm(request.form)
    #if request.method == 'POST' and form.validate():
    return render_template('register.html', form=form)

if __name__ == '__main__':
    app.run(debug=True)

这是我的 app/registration_form.py 文件

from wtforms import Form, BooleanField, TextField, PasswordField, validators

class RegistrationForm(Form):
    first_name = TextField('First Name', [validators.Length(min=2, max=25)])
    last_name = TextField('Last Name', [validators.Length(min=4, max=35)])
    email = TextField('Email', [validators.Email()])
    zip_code = TextField('Zip Code', [validators.Length(min=4, max=35)])
    accept_tos = BooleanField('I accept the TOS', [validators.Required()])

我应该在我的 Procfile 中添加什么来导入注册表单?当我在本地运行应用程序时,它运行良好,所以我觉得它与 Gunicorn 的配置方式有关。

【问题讨论】:

【参考方案1】:

Python 3.x 不支持您使用的相对导入方式。您需要更新您的导入:

from .registration_form import RegistrationForm

或者,您可以执行绝对导入:

from app.registration_form import RegistrationForm

【讨论】:

太棒了!那成功了。谢谢你这么快回答我的问题

以上是关于部署到 Heroku 时,如何在 Procfile 中导入带有 Gunicorn 的自定义模块?的主要内容,如果未能解决你的问题,请参考以下文章

Heroku 服务器中 Procfile 和 Procfile.Windows 之间的区别

Heroku中“Procfile声明类型->(无)”的原因是啥?

如何将 vuejs 项目部署到 heroku

如何设置 Heroku 配置文件,使其在 Heroku 部署的任何终端问题中接受“是”

Heroku for Django 1.8 的 Procfile

将机器人部署到 Heroku 的困难