Heroku平台
Heroku
平台的灵活性极高且支持多种编程语言。若想把程序部署到Heroku
上,开发者要使用Git
把程序推送到Heroku
的Git
服务器上。在服务器上,git push
命令会自动触发安装、配置和部署程序。
Heroku
使用名为Dyno
的计算单元衡量用量,并以此为依据收取服务费用。最常用的Dyno
类型是Web Dyno
,表示一个Web
服务器实例。程序可以通过使用更多的Web Dyno
以增强其请求处理能力。另一种Dyno
类型是Worker Dyno
,用来执行后台作业或其他辅助任务。
Heroku
提供了大量的插件和扩展,可用于数据库、电子邮件支持和其他很多服务。
准备程序
若想使用 Heroku,程序必须托管在 Git 仓库中。如果你的程序托管在像 GitHub 或 BitBucket 这样的远程 Git 服务器上,那么在本地 clone 程序后会创建一个本地 Git 仓库,可无缝用于 Heroku。如果你的程序没有托管在 Git 仓库中,那么必须在开发电脑上创建一个仓库。
注册Heroku账户
安装Heroku Toolbelt
Heroku Toolbelt
是用于创建、管理Heroku
上apps
的命令行工具
heroku 的命令行客户端将被安装到/usr/local/heroku
,同时,/usr/local/heroku/bin
将被添加到你的PATH
环境变量
下载并安装完成后,在 shell 中输入heroku login
,用创建heroku
账号的email
和密码
登陆
$ heroku login
Enter your Heroku credentials.
Email: adam@example.com
Password (typing will be hidden):
Authentication successful.
把你的 SSH 公钥上传到 Heroku,这一点很重要,上传后才能使用 git push 命令。正常情况下,login 命令会自动创建并上传 SSH 公钥。
创建程序
首先要确保程序在 Git 源码控制系统中,然后在程序的顶级目录下运行创建命令
在 Heroku 创建一个 app, 以便 Heroku 准备好接收你的代码
当你创建一个 app, 将创建并关联一个名为
heroku
的远端到你的本地仓库
apps:create [NAME] # create a new app
名称必须以字母开始,只能包含小写字母,数字和连字符, 而且名称在 heroku 的所有程序中必须是唯一的
➜ flask_blog git:(rest) ✗ heroku apps:create flask-blog-chaonet
Creating flask-blog-chaonet... done, stack is cedar-14
https://flask-blog-chaonet.herokuapp.com/ | https://git.heroku.com/flask-blog-chaonet.git
Git remote heroku added
查看已创建的 app
➜ flask_blog git:(rest) ✗ heroku apps
=== My Apps
flask-blog-chaonet
默认 Heroku 会为你的 app 生成一个随机的名字, 或者 你可以通过可选参数指定你的 app名。
现在,你可以向 Heroku 部署你的代码了
$ git push heroku master
# 必须将 本地 的 master push 到 heroku 的 master
应用现在已经部署了,确保至少一个 app 的实例正在运行:
$ heroku ps:scale web=1
现在,可以用创建的包含 app 名称的 URL 访问 app. 有一个便捷的方法, 你可以像这样打开web站点:
$ heroku open
配置数据库
Heroku 以扩展形式支持 Postgres 数据库。少于 1 万条记录、同时连接数 20 、没有缓存 、不允许fork/follow、没有 Postgres 日志 的小型数据库无需付费即可添加 到程序中。
添加 Postgres 到 Heroku 应用
通过命令行,将 Heroku Postgres 添加到一个 Heroku 应用:
➜ flask_blog git:(rest) ✗ heroku addons:create heroku-postgresql:hobby-dev
Creating postgresql-sinuous-8326... done, (free)
Adding postgresql-sinuous-8326 to flask-blog-chaonet... done
Setting DATABASE_URL and restarting flask-blog-chaonet... done, v3
Database has been created and is available
! This database is empty. If upgrading, you can transfer
! data from another database with pg:copy
Use `heroku addons:docs heroku-postgresql` to view documentation.
最低等级的业余版本有两种方案 hobby-dev 和 hobby-basic
一旦 Heroku Postgres 被添加,一个 DATABASE_URL 设置将在 app 配置中生效,并包含用于访问新提供的 Heroku Postgres 服务的 URL 。
这可以使用 heroku config 命令确认:
➜ flask_blog git:(rest) ✗ heroku config -s | grep DATABASE_URL
DATABASE_URL=postgres://bjtrukgnhvnban:T0_N_OWYVz6NnasUwOf0FxVscO@ec2-54-83-52-71.compute-1.amazonaws.com:5432/d44ph8k76dl0h0
amazonaws ?
- 建立主数据库
Heroku 中的每个程序都支持多个数据库。Heroku 建议使用 DATABASE_URL 变量保存主用数据库信息。在单个数据库的情况下,新的数据库已经被指定到 DATABASE_URL 。
对于多个数据库的情况,可以设置主用数据库:
$ heroku pg:promote HEROKU_POSTGRESQL_RED
Promoting HEROKU_POSTGRESQL_RED_URL to DATABASE_URL... done
DATABASE_URL 环境变量的格式正是 SQLAlchemy 所需的。回想一下 config.py 脚本的内容,如果 设定了 DATABASE_URL,就使用其中保存的值,所以现在程序可以自动连接到 Postgres 数据库。
- 查看数据库使用信息
➜ flask_blog git:(rest) ✗ heroku pg:info
=== DATABASE_URL
Plan: Hobby-dev
Status: Available
Connections: 0/20
PG Version: 9.4.5
Created: 2016-01-09 02:57 UTC
Data Size: 6.7 MB
Tables: 0
Rows: 0/10000 (In compliance)
Fork/Follow: Unsupported
Rollback: Unsupported
Add-on: postgresql-sinuous-8326
在 MAC 中安装 Postgres
推荐在本地开发环境与生产环境运行相同的数据库
使用Postgres.app
,是在 Mac 下使用PostgreSQL
的最简单的方法
在postgresapp下载Postgres.app
解压后将Postgres
移到应用程序
文件夹
双击,然后你的 MAC 中就有一个PostgreSQL
服务器在运行了
- 使用 Postgres.app 的命令行工具
配置$PATH
变量
➜ psycopg2-2.6.1 which psql
psql not found
➜ psycopg2-2.6.1 export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/latest/bin
➜ psycopg2-2.6.1 which psql
/Applications/Postgres.app/Contents/Versions/latest/bin/psql
通过命令psql
连接你的数据库
➜ psycopg2-2.6.1 psql -h localhost
psql (9.5.0)
Type "help" for help.
chao-# \q
➜ psycopg2-2.6.1
Using Command Line Tools with Postgres.app
与 Python 对接
➜ psycopg2-2.6.1 pip install psycopg2
Collecting psycopg2
Using cached psycopg2-2.6.1.tar.gz
Building wheels for collected packages: psycopg2
Running setup.py bdist_wheel for psycopg2
Stored in directory: /Users/chao/Library/Caches/pip/wheels/e2/9a/5e/7b620848bbc7cfb9084aafea077be11618c2b5067bd532f329
Successfully built psycopg2
Installing collected packages: psycopg2
Successfully installed psycopg2-2.6.1
遇到的问题:
没有通过 postgres.app 安装 Postgres,就安装 psycopg2 ,结果报错
- pip 安装
➜ flask_blog git:(rest) ✗ pip install psycopg2
Collecting psycopg2
Using cached psycopg2-2.6.1.tar.gz
Complete output from command python setup.py egg_info:
running egg_info
creating pip-egg-info/psycopg2.egg-info
writing pip-egg-info/psycopg2.egg-info/PKG-INFO
writing top-level names to pip-egg-info/psycopg2.egg-info/top_level.txt
writing dependency_links to pip-egg-info/psycopg2.egg-info/dependency_links.txt
writing manifest file 'pip-egg-info/psycopg2.egg-info/SOURCES.txt'
warning: manifest_maker: standard file '-c' not found
Error: pg_config executable not found.
Please add the directory containing pg_config to the PATH
or specify the full executable path with the option:
python setup.py build_ext --pg-config /path/to/pg_config build ...
or with the pg_config option in 'setup.cfg'.
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /private/var/folders/36/tdbs35wx1sx4d6nm4hrmwy0h0000gn/T/pip-build-XR5kDF/psycopg2
- 下载安装包安装
➜ psycopg2-2.6.1 ls
AUTHORS LICENSE MANIFEST.in NEWS README.rst examples psycopg setup.cfg tests
INSTALL MANIFEST Makefile PKG-INFO doc lib scripts setup.py
➜ psycopg2-2.6.1 python setup.py build
running build
running build_py
creating build
creating build/lib.macosx-10.6-intel-2.7
creating build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/__init__.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/_json.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/_range.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/errorcodes.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/extensions.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/extras.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/pool.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/psycopg1.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/tz.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
creating build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/__init__.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/dbapi20.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/dbapi20_tpc.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_async.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_bug_gc.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_bugX000.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_cancel.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_connection.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_copy.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_cursor.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_dates.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_extras_dictcursor.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_green.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_lobject.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_module.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_notify.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_psycopg2_dbapi20.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_quote.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_transaction.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_types_basic.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_types_extras.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_with.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/testconfig.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/testutils.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
running build_ext
Error: pg_config executable not found.
Please add the directory containing pg_config to the PATH
or specify the full executable path with the option:
python setup.py build_ext --pg-config /path/to/pg_config build ...
or with the pg_config option in 'setup.cfg'.
➜ psycopg2-2.6.1
配置 Python 用于 Postgres.app
在 Flask 中使用 Flask-SQLAlchemy 扩展时,可以直接在配置中定义,并由 app 读取。
配置日志
任何写到 标准输出(stdout) 或标准错误(stderr) 的信息才会被 Heroku 抓取到日志,并在 Heroku 客户端通过heroku logs
命令查看。
config.py
# 输出到 stderr,以便被 Heroku 抓取到 logs
import logging
from logging import StreamHandler
file_handler = StreamHandler()
file_handler.setLevel(logging.WARNING)
app.logger.addHandler(file_handler)
定义配置变量
Heroku 可以让你在程序外部配置变量 —— 存储类似加密密钥
或外部资源地址
的数据。
在运行时, 配置的变量被当做环境变量暴露给应用。
变量可以用Heroku
的命令行工具配置,也可以在应用的Dashboard
页面的settings
页签下配置。
配置电子邮件
Heroku 没有提供 SMTP 服务器,所以我们要配置一个外部服务器。很多第三方扩展能把 适用于生产环境的邮件发送服务集成到 Heroku 中,但对于测试和评估而言,使用继承自 Config 基类的 mail 配置已经足够了。
由于直接把安全密令写入脚本存在安全隐患,所以我们把访问 mail SMTP服务器的用户 名和密码保存在环境变量中。
运行生产 Web 服务器
Heroku 没有为托管程序提供 Web 服务器,相反,它希望程序启动自己的服务器并监听环 境变量 PORT 中设定的端口。
Flask 自带的开发 Web 服务器表现很差,因为它不是为生产环境设计的服务器。有两个 可以在生产环境中使用、性能良好且支持 Flask 程序的服务器,分别是Gunicorn和uWSGI。
若想在本地测试 Heroku 配置,我们最好在虚拟环境中安装 Web 服务器。例如,可通过如下命令安装 Gunicorn:
(venv) $ pip install gunicorn
若要使用 Gunicorn 运行程序,可执行下面的命令:
(venv) $ gunicorn manage:app
2013-12-03 09:52:10 [14363] [INFO] Starting gunicorn 18.0
2013-12-03 09:52:10 [14363] [INFO] Listening at: http://127.0.0.1:8000 (14363)
2013-12-03 09:52:10 [14363] [INFO] Using worker: sync
2013-12-03 09:52:10 [14368] [INFO] Booting worker with pid: 14368
manage:app 参数冒号左边的部分表示定义程序的包或者模块
,冒号右边的部分表示包中程序实例的名字
。注意,Gunicor 默认使用端口 8000,而 Flask 默认使用 5000。
添加依赖需求文件
Heroku 从程序顶级文件夹下的 requirements.txt 文件中加载包依赖。这个文件中的所有依赖都会在部署过程中导入 Heroku 创建的虚拟环境。
Heroku 的需求文件必须包含程序在生产环境中使用的所有通用依赖,以及支持 Postgres 数据库的 psycopg2 包和 Gunicorn Web 服务器。
可以在需求文件中导入需求文件。
requirements.txt
-r requirements/prod.txt
gunicorn==18.0
psycopg2==2.5.1
添加Procfile文件
Heroku 需要知道使用哪个命令启动程序。命令在一个名为Procfile
(没有后缀)的特殊文件中指定。这个文件必须放在程序的顶级文件夹中。
web: gunicorn manage:app
Procfile
文件内容的格式很简单:在每一行中指定一个任务名,后跟一个冒号,然后是执行这个任务的命令。名为web
的任务比较特殊任务,Heroku 使用这个任务启动 Web 服务器。
Heroku 会为这个任务提供一个PORT
环境变量,用于设定程序监听请求的端口。如果设定了PORT
变量, Gunicorn
默认就会使用其中保存的值,因此无需将其包含在启动命令中。
部署程序后,Heroku 会运行 Procfile 中列出的所有任务。
程序可在 Procfile 中使用 web 之外的名字声明其他任务,例如程序所需的其他服务。
使用 Heroku Local 进行本地测试
Heroku Local
作为Heroku Toolbelt
的一部分, 自动被安装。
- 在本地启动所有在你的
Profile
中定义的任务
$ heroku local
heroku local
是heroku local:start
的简写,作用相同
➜ flask_blog git:(rest) ✗ heroku local
Downloading forego-0.16.1 to /Users/chao/.heroku... done
forego | starting web.1 on port 5000
web.1 | [2016-01-10 00:11:00 +0800] [17093] [INFO] Starting gunicorn 19.4.5
web.1 | [2016-01-10 00:11:00 +0800] [17093] [INFO] Listening at: http://0.0.0.0:5000 (17093)
web.1 | [2016-01-10 00:11:00 +0800] [17093] [INFO] Using worker: sync
web.1 | [2016-01-10 00:11:00 +0800] [17096] [INFO] Booting worker with pid: 17096
指定运行的端口
➜ flask_blog git:(rest) ✗ heroku local -p 8000
forego | starting web.1 on port 8000
web.1 | [2016-01-10 00:20:22 +0800] [17237] [INFO] Starting gunicorn 19.4.5
web.1 | [2016-01-10 00:20:22 +0800] [17237] [INFO] Listening at: http://0.0.0.0:8000 (17237)
web.1 | [2016-01-10 00:20:22 +0800] [17237] [INFO] Using worker: sync
web.1 | [2016-01-10 00:20:22 +0800] [17240] [INFO] Booting worker with pid: 17240
web.1 | [2016-01-10 00:21:11 +0800] [17237] [CRITICAL] WORKER TIMEOUT (pid:17240)
web.1 | [2016-01-10 00:21:11 +0800] [17240] [INFO] Worker exiting (pid: 17240)
web.1 | [2016-01-10 00:21:11 +0800] [17244] [INFO] Booting worker with pid: 17244
可以在本地指定运行一个特定的进程类型,例如web
或worker
$ heroku local web
然后,你就可以在本地测试 app。使用Ctrl+C
停止
- 设置本地环境变量
在本地运行 APP,同样需要输入一系列 配置变量 作为 app 的配置。.env
文件让你可以收集 app 在本地运行所需要的配置变量。当使用heroku local
命令运行 APP,将会读取.env
文件,并且,每一个 名称/值 对会被插入环境中,模仿实际的配置变量。
增加一个配置变量到你的.env
文件:编辑.env
文件,并在新的一行增加一个新name=value
对。
由于.env
文件中包含密码和其他敏感的账户信息, 所以决不能将其添加到 Git 仓库中,这个文件应该只在存在于本地配置中。使用:echo .env >> .gitignore
, 将.env
文件列入 git 的忽略文件列表。
需要注意,你部署的生产 app 可能使用到与本地开发 app 不同的服务。例如,部署的生产 app 可能有一个引用
Heroku Postgres
数据库的DATABASE_URL
配置变量,但你的本地 app可能在.env
文件中有一个引用本地安装的Postgres
的DATABASE_URL
变量。
有时你可能想要在本地使用和 Heroku 环境相同的配置变量。对于每一个你想要添加到.env
文件的配置变量,使用如下命令:
$ heroku config:get CONFIG-VAR-NAME -s >> .env
- 查看环境变量
使用heroku config
查看 app 的所有配置变量。使用cat .env
查看.env
文件的内容
- 另一个本地测试工具 Foreman
除了heroku local
,原本的foreman
也可以使用,但不再提供官方的支持,需要另外安装。
Heroku Local has replaced Foreman in the Heroku Toolbelt
执行 git push 命令部署
部署过程的最后一步是把程序上传到 Heroku 服务器。在此之前,你要确保所有改动都已经提交到本地Git仓库,然后执行git push heroku master
把程序上传到远程仓库heroku
。
上传代码,中间遇到一个坑,一开始从本地的rest
分支向heroku
的master
推送,报错
➜ flask_blog git:(rest) git push heroku master
Counting objects: 315, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (309/309), done.
Writing objects: 100% (315/315), 82.51 KiB | 0 bytes/s, done.
Total 315 (delta 190), reused 3 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote:
remote: ! Push rejected, no Cedar-supported app detected
remote: HINT: This occurs when Heroku cannot detect the buildpack
remote: to use for this application automatically.
remote: See https://devcenter.heroku.com/articles/buildpacks
remote:
remote: Verifying deploy....
remote:
remote: ! Push rejected to flask-blog-chaonet.
remote:
To https://git.heroku.com/flask-blog-chaonet.git
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/flask-blog-chaonet.git'
➜ flask_blog git:(rest) heroku buildpacks:set heroku/python
Buildpack set. Next release on flask-blog-chaonet will use heroku/python.
Run git push heroku master to create a new release using this buildpack.
➜ flask_blog git:(rest) git push heroku master
Counting objects: 315, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (309/309), done.
Writing objects: 100% (315/315), 82.56 KiB | 0 bytes/s, done.
Total 315 (delta 190), reused 3 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Using set buildpack heroku/python
remote:
remote: ! Push rejected, failed to detect set buildpack heroku/python
remote: More info: https://devcenter.heroku.com/articles/buildpacks#detection-failure
remote:
remote: Verifying deploy....
remote:
remote: ! Push rejected to flask-blog-chaonet.
remote:
To https://git.heroku.com/flask-blog-chaonet.git
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/flask-blog-chaonet.git'
感觉可能是 分支名称的问题,尝试切换到 master,合并分支后再试
➜ flask_blog git:(rest) git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
➜ flask_blog git:(master) ✗ git merge rest
Updating 40d4e6e..90872cd
Fast-forward
.gitignore | 2 +
Procfile | 1 +
app.db | Bin 76800 -> 83968 bytes
app/__init__.py | 67 +++++----
app/api_1_0/__init__.py | 5 +
app/api_1_0/authentication.py | 59 ++++++++
app/api_1_0/comments.py | 79 +++++++++++
app/api_1_0/decorators.py | 21 +++
app/api_1_0/errors.py | 21 +++
app/api_1_0/posts.py | 74 ++++++++++
app/api_1_0/users.py | 75 ++++++++++
app/auth/__init__.py | 5 +
app/auth/forms.py | 65 +++++++++
app/auth/views.py | 196 ++++++++++++++++++++++++++
app/email.py | 11 ++
app/exceptions.py | 4 +
app/main/__init__.py | 13 ++
app/main/error.py | 12 ++
app/main/forms.py | 69 ++++++++++
app/main/views.py | 401 +++++++++++++++++++++++++++++++++++++++++++++++++++++
app/models.py | 71 +++++++++-
app/templates/_comments.html | 10 +-
app/templates/_posts.html | 12 +-
app/templates/{ => auth/email}/confirm.html | 2 +-
app/templates/auth/email/confirm.txt | 6 +
app/templates/{ => auth/email}/confirmmail.html | 2 +-
app/templates/{ => auth/email}/confirmmail.txt | 2 +-
app/templates/{ => auth}/login.html | 4 +-
app/templates/{ => auth}/register.html | 0
app/templates/{ => auth}/renew.html | 0
app/templates/{ => auth}/unconfirmed.html | 2 +-
app/templates/base.html | 14 +-
app/templates/changepassword.html | 2 +-
app/templates/changepassword.txt | 2 +-
app/templates/confirm.txt | 6 -
app/templates/followers.html | 2 +-
app/templates/{ => main}/index.html | 6 +-
app/templates/main/moderate.html | 16 +++
app/templates/user.html | 14 +-
app/views.py | 1 -
app_pro.db | 0
app_test.db | Bin 0 -> 24576 bytes
config.py | 130 +++++++++++++----
requirements.txt | 43 ++++++
run.py | 114 ++++++++++++++-
test/test_api.py | 71 ++++++++++
test/test_basics.py | 24 ++++
test/test_client.py | 86 ++++++++++++
test/test_selenium.py | 90 ++++++++++++
test/test_user_model.py | 45 +++++-
tmp/coverage/app___init___py.html | 195 ++++++++++++++++++++++++++
tmp/coverage/app_api_1_0_authentication_py.html | 209 ++++++++++++++++++++++++++++
tmp/coverage/app_api_1_0_comments_py.html | 249 +++++++++++++++++++++++++++++++++
tmp/coverage/app_api_1_0_decorators_py.html | 133 ++++++++++++++++++
tmp/coverage/app_api_1_0_errors_py.html | 133 ++++++++++++++++++
tmp/coverage/app_api_1_0_posts_py.html | 239 ++++++++++++++++++++++++++++++++
tmp/coverage/app_api_1_0_users_py.html | 241 ++++++++++++++++++++++++++++++++
tmp/coverage/app_auth_forms_py.html | 221 +++++++++++++++++++++++++++++
tmp/coverage/app_auth_views_py.html | 483 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tmp/coverage/app_email_py.html | 113 +++++++++++++++
tmp/coverage/app_main___init___py.html | 117 ++++++++++++++++
tmp/coverage/app_main_views_py.html | 823 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tmp/coverage/app_models_py.html | 981 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tmp/coverage/coverage_html.js | 512 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tmp/coverage/index.html | 260 ++++++++++++++++++++++++++++++++++
tmp/coverage/jquery.debounce.min.js | 9 ++
tmp/coverage/jquery.hotkeys.js | 99 +++++++++++++
tmp/coverage/jquery.isonscreen.js | 53 +++++++
tmp/coverage/jquery.min.js | 4 +
tmp/coverage/jquery.tablesorter.min.js | 2 +
tmp/coverage/keybd_closed.png | Bin 0 -> 264 bytes
tmp/coverage/keybd_open.png | Bin 0 -> 267 bytes
tmp/coverage/status.json | 1 +
tmp/coverage/style.css | 326 +++++++++++++++++++++++++++++++++++++++++++
74 files changed, 7248 insertions(+), 112 deletions(-)
create mode 100644 Procfile
create mode 100644 app/api_1_0/__init__.py
create mode 100644 app/api_1_0/authentication.py
create mode 100644 app/api_1_0/comments.py
create mode 100644 app/api_1_0/decorators.py
create mode 100644 app/api_1_0/errors.py
create mode 100644 app/api_1_0/posts.py
create mode 100644 app/api_1_0/users.py
create mode 100644 app/auth/__init__.py
create mode 100644 app/auth/forms.py
create mode 100644 app/auth/views.py
create mode 100644 app/email.py
create mode 100644 app/exceptions.py
create mode 100644 app/main/__init__.py
create mode 100644 app/main/error.py
create mode 100644 app/main/forms.py
create mode 100644 app/main/views.py
rename app/templates/{ => auth/email}/confirm.html (75%)
create mode 100644 app/templates/auth/email/confirm.txt
rename app/templates/{ => auth/email}/confirmmail.html (74%)
rename app/templates/{ => auth/email}/confirmmail.txt (50%)
rename app/templates/{ => auth}/login.html (71%)
rename app/templates/{ => auth}/register.html (100%)
rename app/templates/{ => auth}/renew.html (100%)
rename app/templates/{ => auth}/unconfirmed.html (80%)
delete mode 100644 app/templates/confirm.txt
rename app/templates/{ => main}/index.html (81%)
create mode 100644 app/templates/main/moderate.html
create mode 100644 app_pro.db
create mode 100644 app_test.db
create mode 100644 requirements.txt
create mode 100644 test/test_api.py
create mode 100644 test/test_basics.py
create mode 100644 test/test_client.py
create mode 100644 test/test_selenium.py
create mode 100644 tmp/coverage/app___init___py.html
create mode 100644 tmp/coverage/app_api_1_0_authentication_py.html
create mode 100644 tmp/coverage/app_api_1_0_comments_py.html
create mode 100644 tmp/coverage/app_api_1_0_decorators_py.html
create mode 100644 tmp/coverage/app_api_1_0_errors_py.html
create mode 100644 tmp/coverage/app_api_1_0_posts_py.html
create mode 100644 tmp/coverage/app_api_1_0_users_py.html
create mode 100644 tmp/coverage/app_auth_forms_py.html
create mode 100644 tmp/coverage/app_auth_views_py.html
create mode 100644 tmp/coverage/app_email_py.html
create mode 100644 tmp/coverage/app_main___init___py.html
create mode 100644 tmp/coverage/app_main_views_py.html
create mode 100644 tmp/coverage/app_models_py.html
create mode 100644 tmp/coverage/coverage_html.js
create mode 100644 tmp/coverage/index.html
create mode 100644 tmp/coverage/jquery.debounce.min.js
create mode 100644 tmp/coverage/jquery.hotkeys.js
create mode 100644 tmp/coverage/jquery.isonscreen.js
create mode 100644 tmp/coverage/jquery.min.js
create mode 100644 tmp/coverage/jquery.tablesorter.min.js
create mode 100644 tmp/coverage/keybd_closed.png
create mode 100644 tmp/coverage/keybd_open.png
create mode 100644 tmp/coverage/status.json
create mode 100644 tmp/coverage/style.css
➜ flask_blog git:(master) git push heroku master
Counting objects: 491, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (482/482), done.
Writing objects: 100% (491/491), 232.17 KiB | 0 bytes/s, done.
Total 491 (delta 301), reused 2 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Using set buildpack heroku/python
remote: -----> Python app detected
remote: -----> Installing runtime (python-2.7.11)
remote: -----> Installing dependencies with pip
remote: Collecting alembic==0.8.4 (from -r requirements.txt (line 1))
remote: Downloading alembic-0.8.4.tar.gz (950kB)
remote: Collecting bleach==1.4.2 (from -r requirements.txt (line 2))
remote: Downloading bleach-1.4.2-py2.py3-none-any.whl
remote: Collecting blinker==1.4 (from -r requirements.txt (line 3))
remote: Downloading blinker-1.4.tar.gz (111kB)
remote: Collecting coverage==4.0.3 (from -r requirements.txt (line 4))
remote: Downloading coverage-4.0.3.tar.gz (354kB)
remote: Collecting decorator==4.0.6 (from -r requirements.txt (line 5))
remote: Downloading decorator-4.0.6-py2.py3-none-any.whl
remote: Collecting dominate==2.1.16 (from -r requirements.txt (line 6))
remote: Downloading dominate-2.1.16.zip
remote: Collecting Flask==0.10.1 (from -r requirements.txt (line 7))
remote: Downloading Flask-0.10.1.tar.gz (544kB)
remote: Collecting Flask-Bootstrap==3.3.5.7 (from -r requirements.txt (line 8))
remote: Downloading Flask-Bootstrap-3.3.5.7.tar.gz (451kB)
remote: Collecting Flask-HTTPAuth==2.7.0 (from -r requirements.txt (line 9))
remote: Downloading Flask-HTTPAuth-2.7.0.tar.gz
remote: Collecting Flask-Login==0.3.2 (from -r requirements.txt (line 10))
remote: Downloading Flask-Login-0.3.2.tar.gz
remote: Collecting Flask-Mail==0.9.1 (from -r requirements.txt (line 11))
remote: Downloading Flask-Mail-0.9.1.tar.gz (45kB)
remote: Collecting Flask-Markdown==0.3 (from -r requirements.txt (line 12))
remote: Downloading Flask-Markdown-0.3.tar.gz (165kB)
remote: Collecting Flask-Migrate==1.6.0 (from -r requirements.txt (line 13))
remote: Downloading Flask-Migrate-1.6.0.tar.gz
remote: Collecting Flask-Moment==0.5.1 (from -r requirements.txt (line 14))
remote: Downloading Flask-Moment-0.5.1.tar.gz
remote: Collecting Flask-PageDown==0.2.1 (from -r requirements.txt (line 15))
remote: Downloading Flask-PageDown-0.2.1.tar.gz
remote: Collecting Flask-Script==2.0.5 (from -r requirements.txt (line 16))
remote: Downloading Flask-Script-2.0.5.tar.gz (42kB)
remote: Collecting Flask-SQLAlchemy==2.1 (from -r requirements.txt (line 17))
remote: Downloading Flask-SQLAlchemy-2.1.tar.gz (95kB)
remote: Collecting Flask-SSLify==0.1.5 (from -r requirements.txt (line 18))
remote: Downloading Flask-SSLify-0.1.5.tar.gz
remote: Collecting Flask-WTF==0.12 (from -r requirements.txt (line 19))
remote: Downloading Flask_WTF-0.12-py2-none-any.whl
remote: Collecting ForgeryPy==0.1 (from -r requirements.txt (line 20))
remote: Downloading ForgeryPy-0.1.tar.gz
remote: Collecting gunicorn==19.4.5 (from -r requirements.txt (line 21))
remote: Downloading gunicorn-19.4.5-py2.py3-none-any.whl (112kB)
remote: Collecting html5lib==0.9999999 (from -r requirements.txt (line 22))
remote: Downloading html5lib-0.9999999.tar.gz (889kB)
remote: Collecting httpie==0.9.3 (from -r requirements.txt (line 23))
remote: Downloading httpie-0.9.3-py2.py3-none-any.whl (66kB)
remote: Collecting itsdangerous==0.24 (from -r requirements.txt (line 24))
remote: Downloading itsdangerous-0.24.tar.gz (46kB)
remote: Collecting Jinja2==2.8 (from -r requirements.txt (line 25))
remote: Downloading Jinja2-2.8-py2.py3-none-any.whl (263kB)
remote: Collecting Mako==1.0.3 (from -r requirements.txt (line 26))
remote: Downloading Mako-1.0.3.tar.gz (565kB)
remote: Collecting Markdown==2.6.5 (from -r requirements.txt (line 27))
remote: Downloading Markdown-2.6.5.tar.gz (301kB)
remote: Collecting MarkupSafe==0.23 (from -r requirements.txt (line 28))
remote: Downloading MarkupSafe-0.23.tar.gz
remote: Collecting pbr==1.8.1 (from -r requirements.txt (line 29))
remote: Downloading pbr-1.8.1-py2.py3-none-any.whl (89kB)
remote: Collecting psycopg2==2.6.1 (from -r requirements.txt (line 30))
remote: Downloading psycopg2-2.6.1.tar.gz (371kB)
remote: Collecting Pygments==2.0.2 (from -r requirements.txt (line 31))
remote: Downloading Pygments-2.0.2-py2-none-any.whl (672kB)
remote: Collecting python-editor==0.5 (from -r requirements.txt (line 32))
remote: Downloading python-editor-0.5.tar.gz
remote: Collecting requests==2.9.1 (from -r requirements.txt (line 33))
remote: Downloading requests-2.9.1-py2.py3-none-any.whl (501kB)
remote: Collecting selenium==2.48.0 (from -r requirements.txt (line 34))
remote: Downloading selenium-2.48.0-py2-none-any.whl (872kB)
remote: Collecting six==1.10.0 (from -r requirements.txt (line 35))
remote: Downloading six-1.10.0-py2.py3-none-any.whl
remote: Collecting SQLAlchemy==1.0.10 (from -r requirements.txt (line 36))
remote: Downloading SQLAlchemy-1.0.10.tar.gz (4.7MB)
remote: Collecting sqlalchemy-migrate==0.10.0 (from -r requirements.txt (line 37))
remote: Downloading sqlalchemy_migrate-0.10.0-py2-none-any.whl (108kB)
remote: Collecting sqlparse==0.1.18 (from -r requirements.txt (line 38))
remote: Downloading sqlparse-0.1.18.tar.gz (58kB)
remote: Collecting Tempita==0.5.2 (from -r requirements.txt (line 39))
remote: Downloading Tempita-0.5.2.tar.gz
remote: Collecting visitor==0.1.2 (from -r requirements.txt (line 40))
remote: Downloading visitor-0.1.2.tar.gz
remote: Collecting Werkzeug==0.11.2 (from -r requirements.txt (line 41))
remote: Downloading Werkzeug-0.11.2-py2.py3-none-any.whl (304kB)
remote: Collecting wheel==0.24.0 (from -r requirements.txt (line 42))
remote: Downloading wheel-0.24.0-py2.py3-none-any.whl (63kB)
remote: Collecting WTForms==2.0.2 (from -r requirements.txt (line 43))
remote: Downloading WTForms-2.0.2-py27-none-any.whl (128kB)
remote: Installing collected packages: SQLAlchemy, MarkupSafe, Mako, python-editor, alembic, six, html5lib, bleach, blinker, coverage, decorator, dominate, Werkzeug, Jinja2, itsdangerous, Flask, visitor, Flask-Bootstrap, Flask-HTTPAuth, Flask-Login, Flask-Mail, Markdown, Flask-Markdown, Flask-SQLAlchemy, Flask-Script, Flask-Migrate, Flask-Moment, WTForms, Flask-PageDown, Flask-SSLify, Flask-WTF, ForgeryPy, gunicorn, Pygments, requests, httpie, pbr, psycopg2, selenium, sqlparse, Tempita, sqlalchemy-migrate, wheel
remote: Running setup.py install for SQLAlchemy
remote: Running setup.py install for MarkupSafe
remote: Running setup.py install for Mako
remote: Running setup.py install for python-editor
remote: Running setup.py install for alembic
remote: Running setup.py install for html5lib
remote: Running setup.py install for blinker
remote: Running setup.py install for coverage
remote: Running setup.py install for dominate
remote: Running setup.py install for itsdangerous
remote: Running setup.py install for Flask
remote: Running setup.py install for visitor
remote: Running setup.py install for Flask-Bootstrap
remote: Running setup.py install for Flask-HTTPAuth
remote: Running setup.py install for Flask-Login
remote: Running setup.py install for Flask-Mail
remote: Running setup.py install for Markdown
remote: Running setup.py install for Flask-Markdown
remote: Running setup.py install for Flask-SQLAlchemy
remote: Running setup.py install for Flask-Script
remote: Running setup.py install for Flask-Migrate
remote: Running setup.py install for Flask-Moment
remote: Running setup.py install for Flask-PageDown
remote: Running setup.py install for Flask-SSLify
remote: Running setup.py install for ForgeryPy
remote: Running setup.py install for psycopg2
remote: Running setup.py install for sqlparse
remote: Running setup.py install for Tempita
remote: Successfully installed Flask-0.10.1 Flask-Bootstrap-3.3.5.7 Flask-HTTPAuth-2.7.0 Flask-Login-0.3.2 Flask-Mail-0.9.1 Flask-Markdown-0.3 Flask-Migrate-1.6.0 Flask-Moment-0.5.1 Flask-PageDown-0.2.1 Flask-SQLAlchemy-2.1 Flask-SSLify-0.1.5 Flask-Script-2.0.5 Flask-WTF-0.12 ForgeryPy-0.1 Jinja2-2.8 Mako-1.0.3 Markdown-2.6.5 MarkupSafe-0.23 Pygments-2.0.2 SQLAlchemy-1.0.10 Tempita-0.5.2 WTForms-2.0.2 Werkzeug-0.11.2 alembic-0.8.4 bleach-1.4.2 blinker-1.4 coverage-4.0.3 decorator-4.0.6 dominate-2.1.16 gunicorn-19.4.5 html5lib-0.9999999 httpie-0.9.3 itsdangerous-0.24 pbr-1.8.1 psycopg2-2.6.1 python-editor-0.5 requests-2.9.1 selenium-2.48.0 six-1.10.0 sqlalchemy-migrate-0.10.0 sqlparse-0.1.18 visitor-0.1.2 wheel-0.24.0
remote:
remote:
remote: -----> Discovering process types
remote: Procfile declares types -> web
remote:
remote: -----> Compressing... done, 44.6MB
remote: -----> Launching...
remote: Released v7
remote: https://flask-blog-chaonet.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/flask-blog-chaonet.git
* [new branch] master -> master
成功,按照requirements.txt
安装依赖的库
建立运行环境
,数据库
➜ flask_blog git:(master) heroku run python run.py deploy
Running python run.py deploy on flask-blog-chaonet... up, run.6723
/app/.heroku/python/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True to suppress this warning.
warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True to suppress this warning.')
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> c1b387222189, empty message
INFO [alembic.runtime.migration] Running upgrade c1b387222189 -> c4a4f802bdf4, empty message
INFO [alembic.runtime.migration] Running upgrade c4a4f802bdf4 -> 83e0975c0db1, add role permission
INFO [alembic.runtime.migration] Running upgrade 83e0975c0db1 -> ee9c55ba9b22, add user profile
INFO [alembic.runtime.migration] Running upgrade ee9c55ba9b22 -> 431d275d6a70, add user.about_me
INFO [alembic.runtime.migration] Running upgrade 431d275d6a70 -> d6f4efe3ffe1, add User.avatar_hash
INFO [alembic.runtime.migration] Running upgrade d6f4efe3ffe1 -> ac6e9871c9a4, add Post ,relationship with User
INFO [alembic.runtime.migration] Running upgrade ac6e9871c9a4 -> 6f219f6bca6e, add Post.on_changed_body, body_html, db.event.listen
INFO [alembic.runtime.migration] Running upgrade 6f219f6bca6e -> 3aca4362a467, add Follow model, user.followers
ollowed
INFO [alembic.runtime.migration] Running upgrade 3aca4362a467 -> e3cfb10aeab6, add comment model
创建并配置好数据库表之后就可以重启程序了,直接使用下述命令即可:
$ heroku restart
Restarting dynos... done
至此,程序就完全部署好了,可通过 https://<appname>.hero-kuapp.com 访问。
查看日志
不同类型的消息,会通过颜色区分显示
➜ flask_blog git:(master) heroku logs
...
2016-01-10T09:04:16.778460+00:00 heroku[run.6723]: Awaiting client
2016-01-10T09:04:16.871340+00:00 heroku[run.6723]: Starting process with command `python run.py deploy`
2016-01-10T09:04:17.236929+00:00 heroku[run.6723]: State changed from starting to up
2016-01-10T09:04:20.574974+00:00 heroku[run.6723]: State changed from up to complete
2016-01-10T09:04:20.567984+00:00 heroku[run.6723]: Process exited with status 0
2016-01-10T09:14:49.296965+00:00 heroku[web.1]: State changed from up to starting
2016-01-10T09:14:53.791001+00:00 heroku[web.1]: Starting process with command `gunicorn run:app`
2016-01-10T09:14:54.840605+00:00 heroku[web.1]: Stopping all processes with SIGTERM
2016-01-10T09:14:56.154205+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Starting gunicorn 19.4.5
2016-01-10T09:14:56.230606+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [10] [INFO] Booting worker with pid: 10
2016-01-10T09:14:56.154848+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Listening at: http://0.0.0.0:10268 (3)
2016-01-10T09:14:56.154974+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Using worker: sync
2016-01-10T09:14:56.160120+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [9] [INFO] Booting worker with pid: 9
2016-01-10T09:14:56.476881+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [10] [INFO] Worker exiting (pid: 10)
2016-01-10T09:14:56.547413+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Shutting down: Master
2016-01-10T09:14:56.475915+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [9] [INFO] Worker exiting (pid: 9)
2016-01-10T09:14:56.529060+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Handling signal: term
2016-01-10T09:14:56.954815+00:00 app[web.1]: /app/.heroku/python/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True to suppress this warning.
2016-01-10T09:14:56.954818+00:00 app[web.1]: warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True to suppress this warning.')
2016-01-10T09:14:57.283202+00:00 app[web.1]: warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True to suppress this warning.')
2016-01-10T09:14:57.283198+00:00 app[web.1]: /app/.heroku/python/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True to suppress this warning.
2016-01-10T09:14:57.480937+00:00 heroku[web.1]: State changed from starting to up
2016-01-10T09:14:57.513335+00:00 heroku[web.1]: Process exited with status 0
2016-01-10T09:15:06.569626+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=32f4cf3a-d766-441b-bbe1-0e7052a37209 fwd="107.161.27.197" dyno=web.1 connect=0ms service=291ms status=200 bytes=3417
2016-01-10T09:15:09.079151+00:00 heroku[router]: at=info method=GET path="/favicon.ico" host=flask-blog-chaonet.herokuapp.com request_id=4e065440-cb19-420a-834e-8e4d8e4c956c fwd="107.161.27.197" dyno=web.1 connect=1ms service=19ms status=404 bytes=655
2016-01-10T09:15:16.012079+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=ac1e63ac-0133-4cad-adac-66563437c70c fwd="107.161.27.197" dyno=web.1 connect=0ms service=506ms status=200 bytes=3504
2016-01-10T09:15:17.703574+00:00 heroku[router]: at=info method=GET path="/followed" host=flask-blog-chaonet.herokuapp.com request_id=0fc98138-ca6f-4873-8327-4a22f892d432 fwd="107.161.27.197" dyno=web.1 connect=1ms service=13ms status=302 bytes=875
2016-01-10T09:15:18.327896+00:00 heroku[router]: at=info method=GET path="/auth/login?next=%2Ffollowed" host=flask-blog-chaonet.herokuapp.com request_id=8d44ff19-c673-4e61-929e-d6ce89678b3a fwd="107.161.27.197" dyno=web.1 connect=0ms service=25ms status=200 bytes=4071
2016-01-10T09:15:19.085786+00:00 heroku[router]: at=info method=GET path="/favicon.ico" host=flask-blog-chaonet.herokuapp.com request_id=d327a6e7-f26b-4514-8813-c2af94dfd639 fwd="107.161.27.197" dyno=web.1 connect=0ms service=3ms status=404 bytes=655
2016-01-10T09:15:20.795897+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=de598303-d092-4647-8758-9e050d089f2e fwd="107.161.27.197" dyno=web.1 connect=2ms service=23ms status=200 bytes=3504
2016-01-10T09:15:22.840818+00:00 heroku[router]: at=info method=GET path="/auth/login" host=flask-blog-chaonet.herokuapp.com request_id=db4a579c-d80b-4205-963e-53d4f8aeb4a3 fwd="107.161.27.197" dyno=web.1 connect=2ms service=9ms status=200 bytes=4014
2016-01-10T09:15:25.834388+00:00 heroku[router]: at=info method=GET path="/auth/register" host=flask-blog-chaonet.herokuapp.com request_id=32a0d112-6dfa-4c8b-bd25-2bf0296add0d fwd="107.161.27.197" dyno=web.1 connect=2ms service=31ms status=200 bytes=4084
2016-01-10T09:15:28.548938+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=0f731062-0cfe-4e51-8967-13ab87ef03c5 fwd="107.161.27.197" dyno=web.1 connect=2ms service=15ms status=200 bytes=3504
应用程序维护模式
维护时可以设置显示维护信息
➜ flask_blog git:(master) heroku maintenance -h
Usage: heroku maintenance
display the current maintenance status of app
-a, --app APP # app to run command against
-r, --remote REMOTE # git remote of app to run command against
Additional commands, type "heroku help COMMAND" for more details:
maintenance:off # take the app out of maintenance mode
maintenance:on # put the app into maintenance mode
开启显示维护信息
➜ flask_blog git:(master) heroku maintenance:on
Enabling maintenance mode for flask-blog-chaonet... done
页面显示的内容
Application Offline for Maintenance
This application is undergoing maintenance right now. Please check back later.
维护结束后,重新开启应用,正常访问
➜ flask_blog git:(master) heroku maintenance:off
Disabling maintenance mode for flask-blog-chaonet... done