为什么 heroku 无法运行我的烧瓶应用程序。 找不到属性应用程序然后输出错误代码 H10



我已经按如下方式设置了Procfile:web: gunicorn project.main:app

文件夹的主要结构是:

├── DocumentTemplates
├── __pycache__
├── project
├── venv
├── ASLtemplate (with highlighted fields).docx
├── ASLtemplate.docx
├── Procfile
└── requirements.txt

包含应用程序文件(init.py(的项目文件夹的文件结构如下:

├── ASLtemplate.docx
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-37.pyc
│   ├── auth.cpython-37.pyc
│   ├── main.cpython-37.pyc
│   └── models.cpython-37.pyc
├── auth.py
├── db.sqlite
├── main.py
├── models.py
├── static
│   └── css
│       └── main.css
└── templates
├── asl.html
├── base.html
├── index.html
├── login.html
├── profile.html
└── signup.html

我已经使用venv建立了一个虚拟环境。

init.py设置如下:

def create_app():
app = Flask(__name__)

以下是运行heroku日志的日志——tail:

2020-09-29T18:32:07.977864+00:00 app[web.1]: gunicorn.errors.HaltServer: <HaltServer 'App failed to load.' 4>
2020-09-29T18:32:08.062188+00:00 heroku[web.1]: Process exited with status 1
2020-09-29T18:32:08.102117+00:00 heroku[web.1]: State changed from up to crashed
2020-09-29T18:44:56.251473+00:00 heroku[web.1]: State changed from crashed to starting
2020-09-29T18:45:02.993607+00:00 heroku[web.1]: Starting process with command `gunicorn project.main:app`
2020-09-29T18:45:06.098025+00:00 app[web.1]: [2020-09-29 18:45:06 +0000] [4] [INFO] Starting gunicorn 20.0.4
2020-09-29T18:45:06.106493+00:00 app[web.1]: [2020-09-29 18:45:06 +0000] [4] [INFO] Listening at: http://0.0.0.0:50916 (4)
2020-09-29T18:45:06.106495+00:00 app[web.1]: [2020-09-29 18:45:06 +0000] [4] [INFO] Using worker: sync
2020-09-29T18:45:06.106496+00:00 app[web.1]: [2020-09-29 18:45:06 +0000] [10] [INFO] Booting worker with pid: 10
2020-09-29T18:45:06.160003+00:00 app[web.1]: [2020-09-29 18:45:06 +0000] [11] [INFO] Booting worker with pid: 11
2020-09-29T18:45:06.529588+00:00 heroku[web.1]: State changed from starting to up
2020-09-29T18:45:08.596225+00:00 app[web.1]: Failed to find attribute 'app' in 'project.main'.
2020-09-29T18:45:08.597071+00:00 app[web.1]: [2020-09-29 18:45:08 +0000] [11] [INFO] Worker exiting (pid: 11)
2020-09-29T18:45:08.598356+00:00 app[web.1]: Failed to find attribute 'app' in 'project.main'.
2020-09-29T18:45:08.600459+00:00 app[web.1]: [2020-09-29 18:45:08 +0000] [10] [INFO] Worker exiting (pid: 10)
2020-09-29T18:45:08.820812+00:00 app[web.1]: [2020-09-29 18:45:08 +0000] [4] [INFO] Shutting down: Master
2020-09-29T18:45:08.820963+00:00 app[web.1]: [2020-09-29 18:45:08 +0000] [4] [INFO] Reason: App failed to load.
2020-09-29T18:45:08.932478+00:00 heroku[web.1]: Process exited with status 4
2020-09-29T18:45:08.985154+00:00 heroku[web.1]: State changed from up to crashed
2020-09-29T19:00:00.067160+00:00 heroku[web.1]: State changed from crashed to starting
2020-09-29T19:00:05.516612+00:00 heroku[web.1]: Starting process with command `gunicorn project.main:app`
2020-09-29T19:00:12.630275+00:00 app[web.1]: [2020-09-29 19:00:12 +0000] [4] [INFO] Starting gunicorn 20.0.4
2020-09-29T19:00:12.631218+00:00 app[web.1]: [2020-09-29 19:00:12 +0000] [4] [INFO] Listening at: http://0.0.0.0:10958 (4)
2020-09-29T19:00:12.631383+00:00 app[web.1]: [2020-09-29 19:00:12 +0000] [4] [INFO] Using worker: sync
2020-09-29T19:00:12.636264+00:00 app[web.1]: [2020-09-29 19:00:12 +0000] [10] [INFO] Booting worker with pid: 10
2020-09-29T19:00:12.720667+00:00 app[web.1]: [2020-09-29 19:00:12 +0000] [11] [INFO] Booting worker with pid: 11
2020-09-29T19:00:12.750328+00:00 heroku[web.1]: State changed from starting to up
2020-09-29T19:00:14.230055+00:00 app[web.1]: Failed to find attribute 'app' in 'project.main'.
2020-09-29T19:00:14.230590+00:00 app[web.1]: [2020-09-29 19:00:14 +0000] [10] [INFO] Worker exiting (pid: 10)
2020-09-29T19:00:14.237015+00:00 app[web.1]: Failed to find attribute 'app' in 'project.main'.
2020-09-29T19:00:14.237903+00:00 app[web.1]: [2020-09-29 19:00:14 +0000] [11] [INFO] Worker exiting (pid: 11)
2020-09-29T19:00:14.409268+00:00 app[web.1]: [2020-09-29 19:00:14 +0000] [4] [INFO] Shutting down: Master
2020-09-29T19:00:14.409455+00:00 app[web.1]: [2020-09-29 19:00:14 +0000] [4] [INFO] Reason: App failed to load.
2020-09-29T19:00:14.489879+00:00 heroku[web.1]: Process exited with status 4
2020-09-29T19:00:14.535226+00:00 heroku[web.1]: State changed from up to crashed
2020-09-29T19:12:14.128289+00:00 heroku[web.1]: State changed from crashed to starting
2020-09-29T19:12:21.431328+00:00 heroku[web.1]: Starting process with command `gunicorn project.main:app`
2020-09-29T19:12:25.672307+00:00 app[web.1]: [2020-09-29 19:12:25 +0000] [4] [INFO] Starting gunicorn 20.0.4
2020-09-29T19:12:25.756186+00:00 app[web.1]: [2020-09-29 19:12:25 +0000] [4] [INFO] Listening at: http://0.0.0.0:18652 (4)
2020-09-29T19:12:25.756317+00:00 app[web.1]: [2020-09-29 19:12:25 +0000] [4] [INFO] Using worker: sync
2020-09-29T19:12:25.775055+00:00 app[web.1]: [2020-09-29 19:12:25 +0000] [10] [INFO] Booting worker with pid: 10
2020-09-29T19:12:25.808464+00:00 app[web.1]: [2020-09-29 19:12:25 +0000] [11] [INFO] Booting worker with pid: 11
2020-09-29T19:12:25.914423+00:00 heroku[web.1]: State changed from starting to up
2020-09-29T19:12:34.388362+00:00 app[web.1]: Failed to find attribute 'app' in 'project.main'.
2020-09-29T19:12:34.389204+00:00 app[web.1]: [2020-09-29 19:12:34 +0000] [11] [INFO] Worker exiting (pid: 11)
2020-09-29T19:12:34.576332+00:00 app[web.1]: Failed to find attribute 'app' in 'project.main'.
2020-09-29T19:12:34.597609+00:00 app[web.1]: [2020-09-29 19:12:34 +0000] [10] [INFO] Worker exiting (pid: 10)
2020-09-29T19:12:34.795394+00:00 app[web.1]: [2020-09-29 19:12:34 +0000] [4] [INFO] Shutting down: Master
2020-09-29T19:12:34.795487+00:00 app[web.1]: [2020-09-29 19:12:34 +0000] [4] [INFO] Reason: App failed to load.
2020-09-29T19:12:34.966714+00:00 heroku[web.1]: Process exited with status 4
2020-09-29T19:12:35.011997+00:00 heroku[web.1]: State changed from up to crashed
2020-09-29T19:49:34.176808+00:00 heroku[web.1]: State changed from crashed to starting
2020-09-29T19:49:45.294429+00:00 heroku[web.1]: Starting process with command `gunicorn project.main:app`
2020-09-29T19:49:48.679247+00:00 app[web.1]: [2020-09-29 19:49:48 +0000] [4] [INFO] Starting gunicorn 20.0.4
2020-09-29T19:49:48.680456+00:00 app[web.1]: [2020-09-29 19:49:48 +0000] [4] [INFO] Listening at: http://0.0.0.0:56983 (4)
2020-09-29T19:49:48.680682+00:00 app[web.1]: [2020-09-29 19:49:48 +0000] [4] [INFO] Using worker: sync
2020-09-29T19:49:48.689348+00:00 app[web.1]: [2020-09-29 19:49:48 +0000] [10] [INFO] Booting worker with pid: 10
2020-09-29T19:49:48.781219+00:00 app[web.1]: [2020-09-29 19:49:48 +0000] [11] [INFO] Booting worker with pid: 11
2020-09-29T19:49:48.956917+00:00 heroku[web.1]: State changed from starting to up
2020-09-29T19:49:52.796205+00:00 app[web.1]: Failed to find attribute 'app' in 'project.main'.
2020-09-29T19:49:52.796951+00:00 app[web.1]: Failed to find attribute 'app' in 'project.main'.
2020-09-29T19:49:52.797320+00:00 app[web.1]: [2020-09-29 19:49:52 +0000] [10] [INFO] Worker exiting (pid: 10)
2020-09-29T19:49:52.797812+00:00 app[web.1]: [2020-09-29 19:49:52 +0000] [11] [INFO] Worker exiting (pid: 11)
2020-09-29T19:49:52.947698+00:00 app[web.1]: Traceback (most recent call last):
2020-09-29T19:49:52.947957+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 209, in run
2020-09-29T19:49:52.948521+00:00 app[web.1]: self.sleep()
2020-09-29T19:49:52.948747+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 357, in sleep
2020-09-29T19:49:52.949188+00:00 app[web.1]: ready = select.select([self.PIPE[0]], [], [], 1.0)
2020-09-29T19:49:52.949239+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 242, in handle_chld
2020-09-29T19:49:52.949738+00:00 app[web.1]: self.reap_workers()
2020-09-29T19:49:52.949790+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 528, in reap_workers
2020-09-29T19:49:52.950313+00:00 app[web.1]: raise HaltServer(reason, self.APP_LOAD_ERROR)
2020-09-29T19:49:52.950574+00:00 app[web.1]: gunicorn.errors.HaltServer: <HaltServer 'App failed to load.' 4>
2020-09-29T19:49:52.950654+00:00 app[web.1]: 
2020-09-29T19:49:52.950854+00:00 app[web.1]: During handling of the above exception, another exception occurred:
2020-09-29T19:49:52.950855+00:00 app[web.1]: 
2020-09-29T19:49:52.950995+00:00 app[web.1]: Traceback (most recent call last):
2020-09-29T19:49:52.951557+00:00 app[web.1]: File "/app/.heroku/python/bin/gunicorn", line 8, in <module>
2020-09-29T19:49:52.951806+00:00 app[web.1]: sys.exit(run())
2020-09-29T19:49:52.951816+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 58, in run
2020-09-29T19:49:52.951992+00:00 app[web.1]: WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
2020-09-29T19:49:52.951997+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/base.py", line 228, in run
2020-09-29T19:49:52.952598+00:00 app[web.1]: super().run()
2020-09-29T19:49:52.952635+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/base.py", line 72, in run
2020-09-29T19:49:52.953094+00:00 app[web.1]: Arbiter(self).run()
2020-09-29T19:49:52.953128+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 229, in run
2020-09-29T19:49:52.953480+00:00 app[web.1]: self.halt(reason=inst.reason, exit_status=inst.exit_status)
2020-09-29T19:49:52.953515+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 342, in halt
2020-09-29T19:49:52.954159+00:00 app[web.1]: self.stop()
2020-09-29T19:49:52.954195+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 393, in stop
2020-09-29T19:49:52.954683+00:00 app[web.1]: time.sleep(0.1)
2020-09-29T19:49:52.954813+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 242, in handle_chld
2020-09-29T19:49:52.955339+00:00 app[web.1]: self.reap_workers()
2020-09-29T19:49:52.955372+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 528, in reap_workers
2020-09-29T19:49:52.955923+00:00 app[web.1]: raise HaltServer(reason, self.APP_LOAD_ERROR)
2020-09-29T19:49:52.956009+00:00 app[web.1]: gunicorn.errors.HaltServer: <HaltServer 'App failed to load.' 4>
2020-09-29T19:49:53.055558+00:00 heroku[web.1]: Process exited with status 1
2020-09-29T19:49:53.105196+00:00 heroku[web.1]: State changed from up to crashed
2020-09-29T19:58:46.539326+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=arcane-garden-63637.herokuapp.com request_id=c622b774-6456-4cca-a956-218d8eb374d9 fwd="82.27.141.178" dyno= connect= service= status=503 bytes= protocol=https
2020-09-29T19:58:47.073950+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=arcane-garden-63637.herokuapp.com request_id=7ce1d466-4193-4cca-be91-5b771158bc28 fwd="82.27.141.178" dyno= connect= service= status=503 bytes= protocol=https

这是init.py:中的代码

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import environ
from flask_login import LoginManager
from flask_pure import Pure
# init SQLAlchemy so we can use it later in our models
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = xxxx
app.config['SQLALCHEMY_DATABASE_URI'] = environ.get('DATABASE_URL') or 'sqlite:///db.sqlite'
app.config['PURECSS_RESPONSIVE_GRIDS'] = True
app.config['PURECSS_USE_CDN'] = True
app.config['PURECSS_USE_MINIFIED'] = True
Pure(app)
db.init_app(app)
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
from .models import User
@login_manager.user_loader
def load_user(user_id):
# since the user_id is just the primary key of our user table, use it in the query for the user
return User.query.get(int(user_id))
# blueprint for auth routes in our app
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
# blueprint for non-auth parts of app
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app

这是来自main.py 的代码

from flask_login import login_required, current_user
from . import db
from os import environ
from flask import Flask, render_template, request, send_file, redirect, Blueprint
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, SelectField, IntegerField, TextAreaField
from wtforms.fields.html5 import DateField
from flask_sqlalchemy import SQLAlchemy
from wtforms.validators import DataRequired
from docx import Document
import jinja2
from docxtpl import DocxTemplate
from io import StringIO
import io
from flask_bootstrap import Bootstrap
from flask_pure import Pure
main = Blueprint('main', __name__)
class MyForm(FlaskForm):
client_name=StringField('Client Contact', validators=[DataRequired()])
client_job_title=StringField('Client Contact Job Title', validators=[DataRequired()])
company_name=StringField('Company Name', validators=[DataRequired()])
# client_name_upper=StringField('Client Contact Name Upper Case', validators=[DataRequired()])
address_line_1=StringField('Address Line 1', validators=[DataRequired()])
address_line_2=StringField('Address Line 2', validators=[DataRequired()])
city_county_country=StringField('City, County, Country', validators=[DataRequired()])
postcode=StringField('Post Code', validators=[DataRequired()])
date=DateField('Date', validators=[DataRequired()], format='%Y-%m-%d')
job_number=StringField('Job Number (4 digit)', validators=[DataRequired()])
document_number=StringField('Document number e.g. 001', validators=[DataRequired()])
lead_initials=StringField('Mabbett Lead Initials e.g. KB for Kieran Bruce', validators=[DataRequired()])
supervisor_initials=StringField('Mabbett Supervisor e.g. PY for Paul Young', validators=[DataRequired()])
supervisor_name=StringField('Mabbett Supervisor Name', validators=[DataRequired()])
project_title=StringField('Project Title', validators=[DataRequired()])
lead_name=StringField('Lead Mabbett Name', validators=[DataRequired()])
service_type=StringField('Service Type', validators=[DataRequired()])
company_short=StringField('Company Name Short Hand e.g. WG&S for William Grant & Sons Ltd ', validators=[DataRequired()])
site_location=StringField('Site Location e.g. Girvan', validators=[DataRequired()])
letter_agreement_date=StringField('Date of orginal letter agreement', validators=[DataRequired()])
project_background=TextAreaField('Background', validators=[DataRequired()])
taskA_title=StringField('Task A Title', validators=[DataRequired()])
taskA_scope=TextAreaField('Task A Scope', validators=[DataRequired()])
taskA_professional_fee=StringField('Task A Professional Fee', validators=[DataRequired()])
taskA_reimbursable_fee=StringField('Task A Reimbursable Fee', validators=[DataRequired()])
taskB_title=StringField('Task B Title', validators=[DataRequired()])
taskB_scope=TextAreaField('Task B Scope', validators=[DataRequired()])
taskB_professional_fee=StringField('Task B Professional Fee', validators=[DataRequired()])
taskB_reimbursable_fee=StringField('Task B Reimbursable Fee', validators=[DataRequired()])
taskC_title=StringField('Task C Title', validators=[DataRequired()])
taskC_scope=TextAreaField('Task C Scope', validators=[DataRequired()])
taskC_professional_fee=StringField('Task C Professional Fee', validators=[DataRequired()])
taskC_reimbursable_fee=StringField('Task C Reimbursable Fee', validators=[DataRequired()])
total_professional_fee=StringField('Total Professional Fee', validators=[DataRequired()])
total_reimbursable_fee=StringField('Total Reimbursable Fee', validators=[DataRequired()])
total_budget=StringField('Total Budget', validators=[DataRequired()])
department_lead_name=StringField('Department Lead Name', validators=[DataRequired()])
department_lead_job_title=StringField('Department Lead Job Title', validators=[DataRequired()])
submit = SubmitField('Create your word file')

@main.route('/')
def index():
return render_template('index.html')
@main.route('/profile')
@login_required
def profile():
return render_template('profile.html', name=current_user.name)
@main.route('/asl', methods=('GET', 'POST'))
@login_required
def asl():
# assigns form to the MyForm Class above
form = MyForm()
# assigns values from the form to the values in a dictionary.
if form.is_submitted():
result = request.form
document = DocxTemplate('ASLtemplate.docx')
context = { 
'client_name':result['client_name'],
'client_job_title':result['client_job_title'],
'company_name':result['company_name'],
# 'client_name_upper':result['client_name_upper'],
'address_line_1':result['address_line_1'],
'address_line_2':result['address_line_2'],
'city_county_country':result['city_county_country'],
'postcode':result['postcode'],
'date':result['date'],
'job_number':result['job_number'],
'document_number':result['document_number'],
'lead_initials':result['lead_initials'],
'supervisor_initials':result['supervisor_initials'],
'supervisor_name':result['supervisor_name'],
'project_title':result['project_title'],
'lead_name':result['lead_name'],
'service_type':result['service_type'],
'company_short':result['company_short'],
'site_location':result['site_location'],
'letter_agreement_date':result['letter_agreement_date'],
'project_background':result['project_background'],
'taskA_title':result['taskA_title'],
'taskA_scope':result['taskA_scope'],
'taskA_professional_fee':result['taskA_professional_fee'],
'taskA_reimbursable_fee':result['taskA_reimbursable_fee'],
'taskB_title':result['taskB_title'],
'taskB_scope':result['taskB_scope'],
'taskB_professional_fee':result['taskB_professional_fee'],
'taskB_reimbursable_fee':result['taskB_reimbursable_fee'],
'taskC_title':result['taskC_title'],
'taskC_scope':result['taskC_scope'],
'taskC_professional_fee':result['taskC_professional_fee'],
'taskC_reimbursable_fee':result['taskC_reimbursable_fee'],
'total_professional_fee':result['total_professional_fee'],
'total_reimbursable_fee':result['total_reimbursable_fee'],
'total_budget':result['total_budget'],
'department_lead_name':result['department_lead_name'],
'department_lead_job_title':result['department_lead_job_title']
}
# Handles the word templating
document.render(context)
file = io.BytesIO()
document.save(file)
file.seek(0)
return send_file(file, attachment_filename=(result["job_number"]+ ".docx"), as_attachment=True)
# blank form will be rendered when the url is visited. The form is based upon the html in the bsf html file 
return render_template('asl.html', form=form)

查看gunicorn的基本用法文档,您将其指向不存在的project.main.app()。根据烧瓶文档的gunicorn章节,我认为如果您将调用更改为:,您应该能够启动您的应用程序

gunicorn "project:create_app()"

如果这不起作用,你将不得不提供一个";应该在指定的模块"中找到的WSGI可调用;(来源(。

最新更新