Heroku部署FastAPI+Selenium出现H14/R10错误解决方案
你的猜想基本符合Heroku的运行规则,两个报错的根因和对应解决方法如下:
根因说明
- Heroku的
worker类型进程属于后台进程,不会被接入平台的HTTP路由层,哪怕你在worker里启动了uvicorn服务,外部请求根本到不了这个进程,所以会抛出H14 No web processes running的503错误,这和你的爬虫逻辑无关,是平台的进程路由规则决定的。 - 改成
web进程后触发R10 Boot timeout,确实是你顶层的爬虫代码阻塞导致的。你把Scraping().get_books()写在了模块顶层,Python加载main.py的时候会先同步执行这段逻辑,等它执行完才会走到uvicorn启动、绑定端口的步骤。Heroku给web进程预留的端口绑定时间只有60秒,你的爬虫要跑2-5分钟,远远超出时间限制,进程会直接被平台强杀。 - 补充一点:不是web进程不能跑爬虫,而是不能把长耗时逻辑放在启动流程里阻塞端口绑定,另外Heroku对单个web请求的超时限制是30秒,直接把2-5分钟的爬虫放在接口请求逻辑里跑也会触发请求超时,长耗时任务本来就应该和web服务拆分。
分步解决方法
核心思路是把API服务和爬虫任务拆成两个独立进程,web进程只负责快速响应接口请求,worker进程专门在后台跑长耗时的爬虫任务,两个进程通过共享存储交换数据。
1. 调整代码结构,解耦爬虫和API启动逻辑
首先删掉顶层直接执行爬虫的代码,不要让爬虫阻塞服务启动。选用Heroku自带的免费Redis插件做共享存储即可,不需要额外搭建服务。
调整后的API主文件main.py示例:
import os import json import redis from fastapi import FastAPI # 导入你自己写的爬虫类 from your_scraping_file import Scraping app = FastAPI() # 连接平台自动注入的Redis实例 redis_conn = redis.from_url(os.getenv("REDIS_URL")) @app.get("/") def home(): """返回已爬取的书籍数据""" cache_data = redis_conn.get("cached_books") if not cache_data: return {"status": "pending", "msg": "首次爬虫任务执行中,请稍后访问"} return {"status": "success", "data": json.loads(cache_data)}
单独新建worker.py作为后台爬虫进程的入口,专门负责跑长耗时爬虫任务:
import os import time import json import redis from your_scraping_file import Scraping redis_conn = redis.from_url(os.getenv("REDIS_URL")) if __name__ == "__main__": while True: # 执行爬虫逻辑 books_result = Scraping().get_books() # 爬取结果写入Redis缓存 redis_conn.set("cached_books", json.dumps(books_result)) # 按需配置爬取间隔,示例为每1小时重新爬取一次 time.sleep(3600)
注意:不要用dict作为变量名,会覆盖Python内置的字典类型,容易引发难以排查的bug;数据序列化用标准json库,不要用eval,避免安全风险。
2. 修改Procfile,同时声明两个进程
把Procfile内容替换为以下两行,分别定义web和worker进程的启动命令:
web: uvicorn main:app --host=0.0.0.0 --port=${PORT:-5000} worker: python worker.py
3. 平台侧配置
- 在Heroku应用后台挂载免费的
heroku-redis插件,插件会自动把REDIS_URL环境变量注入到所有进程中,不需要手动配置连接信息 - 部署完成后,在Resources页面确认web和worker两个dyno都处于开启状态
- 这套配置下web进程启动时没有任何阻塞逻辑,会在几秒内完成端口绑定,不会触发R10超时;worker进程在后台持续执行爬虫任务,爬取结果写入缓存后,接口可以毫秒级响应,不会触发请求超时。
内容的提问来源于stack exchange,提问作者asfa afs
相关产品推荐
相关产品推荐

