使用单独的前端/后端服务器将应用程序部署到Heroku

时间:2017-12-03 17:07:24

标签: ruby-on-rails node.js heroku

我目前正在尝试将应用部署到单个Heroku dyno,它不使用create-react-app但是有一个用于webpack的快速服务器和一个rails API后端。

我遇到快速代理我的API请求的问题(但在本地工作正常),这是Heroku日志的错误:

2017-12-03T16:00:18.436271+00:00 app[web.1]: Error: connect ECONNREFUSED 127.0.0.1:3005
2017-12-03T16:00:18.436308+00:00 app[web.1]:     at Object.exports._errnoException (util.js:1018:11)
2017-12-03T16:00:18.436309+00:00 app[web.1]:     at exports._exceptionWithHostPort (util.js:1041:20)
2017-12-03T16:00:18.436311+00:00 app[web.1]:     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1090:14)

我确保将节点和轨道的buildpack用作described here

以下是相关代码:

Procfile

web: npm run start:prod
api: bundle exec rails server --port=3005 --environment=production -b 127.0.0.1

的package.json

{
  "name": "foo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "proxy": "http://127.0.0.1:3005/",
  "engines": {
    "node": "6.10.2",
    "yarn": "0.24.5",
    "npm": "5.5.1"
  },
  "scripts": {
    "start": "NODE_ENV=development node server",
    "start:prod": "yarn run build && NODE_ENV=production node server",
    "build": "NODE_ENV=production webpack -p --config ./webpack.prod.js --progress --colors --display-error-details"
  },

server.js

const express = require('express');
const proxy = require('express-http-proxy');

const app = express();

const port = process.env.PORT || 3000;
const path = require('path')
const webpack = require('webpack')

const proxyHost = '127.0.0.1';
const proxyPort = '3005';

app.use('/api', proxy(`${proxyHost}:${proxyPort}`));

const isProd = process.env.NODE_ENV === 'production'

let config

if (isProd) {
  config = require('./webpack.prod.js')
} else {
  config = require('./webpack.dev.js')
}

const publicPath = config.output.publicPath || '/';
const outputPath = config.output.path || path.resolve(process.cwd(), 'dist');

if (!isProd) {
  console.log('Development env detected: Initializing hot reloading')
  const webpackDevMiddleware = require('webpack-dev-middleware')
  const webpackHotMiddleware = require('webpack-hot-middleware')
  const compiler = webpack(config)

  app.use(webpackHotMiddleware(compiler, {
    log: console.log,
    path: '/__webpack_hmr'
  }))

  app.use(webpackDevMiddleware(compiler, {
    entry: config.entry,
    publicPath: config.output.publicPath,
    stats: {
      colors: true
    }
  }))

  app.use('*', function (req, res, next) {
    const filename = path.join(compiler.outputPath, 'index.html')
    compiler.outputFileSystem.readFile(filename, (err, result) => {
      if (err) {
        return next(err)
      }
      res.set('content-type', 'text/html')
      res.send(result)
      res.end()
    })
  })

} else {
  app.use(publicPath, express.static(outputPath));
  app.get('*', (req, res) => res.sendFile(path.resolve(outputPath, 'index.html')));
}

app.listen(port, (err) => {
  if (err) {
    console.log(err.message)
  } else {
    console.log(`Server Started at port ${port}`);
  }
});

非常感谢任何帮助!

编辑解决方案

所以我能够根据下面接受的答案找到解决方案,但我想我会更新帖子以详细说明。

正如答案所指出的,似乎Heroku在你的Procfile中每个进程使用不同的dyno,这就是为什么前端/后端服务器最初无法相互通信的原因。

为了避免这种情况,我只是创建了一个虚拟的proc文件,它使用foreman来初始化真正的proc文件:

Procfile(Heroku使用的假人)

web: foreman start -f StartProcfile

StartProcfile(实际流程)

web: npm run start:prod
api: bundle exec rails server --port=3005 --environment=production

应该注意的是,在我的情况下,我遇到了超出dyno内存上限的额外问题,并且花费超过60秒来绑定到指定的heroku端口。事实证明这是因为我将构建步骤作为web进程的一部分,当我应该使用postinstall中的package.json挂钩时。

的package.json

  "scripts": {
    "start": "NODE_ENV=development node server",
    "start:prod": "NODE_ENV=production node server --optimize_for_size --max_old_space_size=460 --gc_interval=100",
    "build": "NODE_ENV=production webpack -p --config ./webpack.prod.js --progress --colors --display-error-details",
    "postinstall": "npm run build"
  },

1 个答案:

答案 0 :(得分:1)

Procfile中的每一行最终都会在一个单独的dyno中运行。如果您需要在同一个dyno上运行这两个进程(在本例中为web),那么您需要重新定义web以调用启动节点服务器的shell脚本,然后启动rails服务器,或让节点启动过程启动rails服务器。

完全披露,我从未真正做过你正在尝试的事情。即使在进行上述更改后,将rails API服务器绑定到端口3005也可能无法正常工作。但是,毫无疑问,127.0.0.1进程中的web永远不会在127.0.0.1进程中api,因为它们将始终在不同的dynos上运行。希望这些信息有所帮助。