Procfile #

什么是 Procfile? #

Procfile 是一个文本文件,用于声明应用的进程类型和启动命令。Heroku 使用 Procfile 来确定如何启动和管理应用进程。

基本语法 #

text
<进程类型>: <命令>

示例 #

text
web: node index.js
worker: node worker.js
clock: node clock.js
release: node migrate.js

进程类型 #

Web 进程 #

Web 进程是唯一能接收外部 HTTP 流量的进程类型。

text
web: node index.js
bash
# Web Dyno 自动接收路由流量
heroku ps:scale web=3  # 启动 3 个 Web Dyno

Worker 进程 #

Worker 进程用于后台任务处理,不接收 HTTP 流量。

text
worker: node worker.js
bash
# 启动 Worker Dyno
heroku ps:scale worker=2

Clock 进程 #

Clock 进程用于定时任务调度。

text
clock: node clock.js
bash
# 启动 Clock Dyno
heroku ps:scale clock=1

Release 进程 #

Release 进程在每次发布时执行一次,用于数据库迁移等任务。

text
release: npm run migrate

进程类型详解 #

类型 说明 自动启动 接收流量
web Web 服务 是(至少 1 个)
worker 后台任务
clock 定时任务
release 发布任务 发布时执行

创建 Procfile #

Node.js 应用 #

text
web: node index.js
worker: node worker.js

Python 应用 #

text
web: gunicorn app:app
worker: python worker.py
clock: python scheduler.py
release: python migrate.py

Ruby 应用 #

text
web: bundle exec puma -C config/puma.rb
worker: bundle exec sidekiq -e production -C config/sidekiq.yml
clock: bundle exec clockwork clock.rb
release: bundle exec rake db:migrate

Java 应用 #

text
web: java -jar target/myapp.jar
worker: java -jar target/worker.jar

Go 应用 #

text
web: bin/server
worker: bin/worker

多进程应用示例 #

完整 Procfile 示例 #

text
web: node server.js
worker: node worker.js
scheduler: node scheduler.js
release: npm run db:migrate

进程架构图 #

text
┌─────────────────────────────────────────┐
│            Heroku 应用                   │
├─────────────────────────────────────────┤
│                                         │
│  ┌─────────────────────────────────┐   │
│  │         Web Dynos               │   │
│  │  ┌─────────┐ ┌─────────┐       │   │
│  │  │ web.1   │ │ web.2   │       │   │
│  │  │ HTTP    │ │ HTTP    │       │   │
│  │  └─────────┘ └─────────┘       │   │
│  └─────────────────────────────────┘   │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │       Worker Dynos              │   │
│  │  ┌─────────┐ ┌─────────┐       │   │
│  │  │worker.1 │ │worker.2 │       │   │
│  │  │ Queue   │ │ Queue   │       │   │
│  │  └─────────┘ └─────────┘       │   │
│  └─────────────────────────────────┘   │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │       Clock Dyno                │   │
│  │  ┌─────────┐                    │   │
│  │  │ clock.1 │                    │   │
│  │  │ Cron    │                    │   │
│  │  └─────────┘                    │   │
│  └─────────────────────────────────┘   │
│                                         │
└─────────────────────────────────────────┘

进程管理 #

查看进程状态 #

bash
# 查看所有进程
heroku ps

# 输出示例
# === web (Eco): node index.js (1)
# web.1: up 2024/01/15 10:30:00 (~ 2h ago)
#
# === worker (Eco): node worker.js (1)
# worker.1: up 2024/01/15 10:30:00 (~ 2h ago)

扩展进程 #

bash
# 扩展 Web Dyno
heroku ps:scale web=3

# 扩展 Worker Dyno
heroku ps:scale worker=5

# 同时扩展多个进程
heroku ps:scale web=2 worker=3

# 缩减到 0
heroku ps:scale worker=0

重启进程 #

bash
# 重启所有进程
heroku restart

# 重启特定进程类型
heroku restart web

# 重启特定 Dyno
heroku restart web.1

停止进程 #

bash
# 停止特定 Dyno
heroku ps:stop web.1

# 停止所有 Worker
heroku ps:stop worker

Release 进程 #

用途 #

Release 进程在每次部署时自动执行,常用于:

  • 数据库迁移
  • 资源编译
  • 缓存预热
  • 数据初始化

示例 #

text
release: npm run db:migrate && npm run seed

数据库迁移示例 #

json
// package.json
{
  "scripts": {
    "db:migrate": "node-pg-migrate up",
    "db:rollback": "node-pg-migrate down",
    "seed": "node scripts/seed.js"
  }
}
text
# Procfile
release: npm run db:migrate
web: node index.js

Release 进程注意事项 #

bash
# Release 进程失败会导致部署失败
# 确保迁移脚本是幂等的

# 查看发布日志
heroku releases:info v10

# 如果 release 失败,回滚
heroku rollback

本地开发 #

Heroku Local #

bash
# 安装 Heroku Local(包含在 Heroku CLI 中)
# 使用 Procfile 本地运行

# 启动所有进程
heroku local

# 启动特定进程
heroku local web
heroku local worker

# 指定端口
heroku local --port 5000

# 指定环境文件
heroku local -f .env.local

.env 文件 #

bash
# .env 文件用于本地环境变量
DATABASE_URL=postgres://localhost:5432/myapp_dev
SECRET_KEY=dev-secret
PORT=3000

Foreman #

bash
# 也可以使用 foreman
gem install foreman

# 启动应用
foreman start

# 启动特定进程
foreman start web

高级配置 #

使用 Shell 脚本 #

text
web: ./scripts/start-web.sh
worker: ./scripts/start-worker.sh
bash
#!/bin/bash
# scripts/start-web.sh

echo "Starting web server..."
node index.js

环境变量配置 #

text
web: NODE_ENV=production node index.js
worker: QUEUE=high node worker.js

多命令组合 #

text
web: npm run build && node index.js
release: npm run db:migrate && npm run cache:warm

常见问题 #

Procfile 未找到 #

bash
# 确保 Procfile 在项目根目录
# 文件名必须是 Procfile(大写 P,无扩展名)

# 检查文件
ls -la Procfile

# 如果使用其他文件名
heroku buildpacks:set heroku/nodejs
# 并确保有 package.json 的 start 脚本

进程启动失败 #

bash
# 查看日志
heroku logs --tail

# 常见原因:
# 1. 命令不存在
# 2. 依赖未安装
# 3. 端口未正确绑定
# 4. 环境变量缺失

Web 进程绑定端口 #

javascript
// 正确:使用 PORT 环境变量
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
});

// 错误:硬编码端口
app.listen(3000);  // Heroku 会分配随机端口

进程超时 #

bash
# Web 进程必须在 60 秒内绑定端口
# Worker 进程没有此限制

# 长时间启动任务
# 1. 使用 release 进程预处理
# 2. 异步初始化

Procfile 最佳实践 #

1. 保持简单 #

text
# 好的做法
web: node index.js

# 避免
web: NODE_ENV=production DEBUG=* node --max-old-space-size=4096 index.js

2. 使用 npm 脚本 #

json
// package.json
{
  "scripts": {
    "start": "node index.js",
    "worker": "node worker.js",
    "migrate": "node-pg-migrate up"
  }
}
text
# Procfile
web: npm start
worker: npm run worker
release: npm run migrate

3. 进程分离 #

text
# 分离关注点
web: node server.js          # 处理 HTTP 请求
worker: node worker.js       # 处理后台任务
scheduler: node cron.js      # 定时任务

4. 健康检查 #

javascript
// 在进程中添加健康检查
process.on('SIGTERM', () => {
  console.log('Received SIGTERM, shutting down gracefully...');
  server.close(() => {
    console.log('Server closed');
    process.exit(0);
  });
});

下一步 #

Procfile 掌握后,接下来学习 Dyno 管理 了解如何管理和扩展应用进程!

最后更新:2026-03-28