Rails 6搭配Webpacker启动内存膨胀及请求超时问题求助
Rails 6 + Webpacker on Heroku: 内存飙升与请求超时解决方案
我之前维护Rails 6应用时也踩过一模一样的坑——升级Webpacker后Heroku启动内存直接冲到1.2GB,还频繁触发H12请求超时。结合你的日志和尝试过的方案,给你几个实际有效的解决思路:
1. 彻底砍掉启动时的Assets编译(最立竿见影)
Heroku默认会在dyno启动时编译Webpack assets,这一步是内存暴涨的核心原因。改成本地预编译assets,把编译好的文件直接推到Heroku:
- 打开
config/webpacker.yml,把生产环境的compile设置为false:production: compile: false - 本地执行预编译命令(确保RAILS_ENV是生产环境):
RAILS_ENV=production bundle exec rails assets:precompile - 把生成的
public/packs目录提交到Git仓库 - 最后在Heroku上禁用自动编译:
这样启动时dyno不用再耗内存编译代码,内存峰值会直接降到稳定值附近,也能避免启动时的请求超时。heroku config:set WEBPACKER_PRECOMPILE=false
2. 优化Puma配置,控制内存占用
默认的rails server在内存控制上不如Puma精细,调整Puma的工作进程和线程数,适配Heroku的512MB dyno:
- 在项目根目录创建
Procfile,指定用Puma启动:web: bundle exec puma -C config/puma.rb - 编辑
config/puma.rb,设置适合的参数(亲测512MB dyno用这个配置很稳):# 根据dyno内存调整,512MB dyno设为1即可 workers Integer(ENV['WEB_CONCURRENCY'] || 1) # 线程数不要太高,避免内存过载 threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5) threads threads_count, threads_count # 预加载应用,减少重复代码的内存消耗 preload_app! rackup DefaultRackup port ENV['PORT'] || 3000 environment ENV['RACK_ENV'] || 'development' # 工作进程启动时重新建立数据库连接 on_worker_boot do ActiveRecord::Base.establish_connection end
3. 排查Webpack打包的冗余代码
虽然你试过懒加载和代码分割,但可能还有隐藏的大体积依赖没处理。用webpack-bundle-analyzer分析打包文件:
- 安装依赖:
yarn add webpack-bundle-analyzer --dev - 在
config/webpack/production.js里添加分析插件:const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const { merge } = require('webpack-merge'); const baseConfig = require('./base'); module.exports = merge(baseConfig, { // 其他生产环境配置... plugins: [ new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false, reportFilename: 'bundle-report.html' }) ] }); - 重新预编译后,打开生成的
bundle-report.html,看看有没有大的第三方库被全局引入,比如某些UI组件库可以改成按需加载,进一步缩小打包体积。
4. 临时规避启动时的请求超时
如果暂时没法完全解决内存问题,可以用这两个小技巧避免H12错误:
- 部署时启用Heroku维护模式:
# 部署前开启 heroku maintenance:on # 部署完成、应用启动稳定后关闭 heroku maintenance:off - 延长Heroku的启动超时时间(默认是60秒,最多可以设到120秒):
heroku config:set HEROKU_DYNO_IDLE_TIMEOUT=120
关于你日志里的H12错误
那个/academy/lessons的请求超时,本质是应用启动时还在处理资源初始化(或者之前的assets编译),没法及时响应请求。上面的预编译和维护模式方案应该能直接解决这个问题。
内容的提问来源于stack exchange,提问作者Maayan Naveh
相关产品推荐
相关产品推荐

