在使用Action Cable(Puma端口侦听)的同时将Ruby on Rails应用程序部署到Heroku

我已经在本地主机环境中使用Action Cable,在这种情况下,我使用包含的简单文件启动Puma服务器

# /bin/bash bundle exec puma -p 28080 cable/config.ru 

一旦发生这种情况,puma服务器就会启动并正在侦听此28080端口以及运行本地服务器的端口。 通过在线搜索,我找不到一个可以告诉我在heroku上模拟这个方法的地方,或者让我的服务器始终在同一个端口上开始的方式(虽然我不知道这是否会给我所需的结果)

我有一个javascript文件设置来创建与该端口相关的消费者。

 //= require cable //= require_self //= require_tree . this.App = {}; App.cable = Cable.createConsumer('ws://127.0.0.1:28080'); 

我想我需要更改127.0.0.1部分以及部署到heroku也可以工作,但我不确定。 我试图切断28080部分并用ENV [‘PORT’]替换它,但它说它是一个未知的变量,即使我有一个puma.rb文件设置,其端口设置为

 ... (only part of the file) rackup DefaultRackup port ENV['PORT'] || 3000 environment ENV['RACK_ENV'] || 'development' ... 

所以在我看来ENV [‘PORT’]被定义为当我检查heroku日志时puma服务器将是

 2015-07-26T06:50:25.278030+00:00 heroku[web.1]: Starting process with command `bin/rails server -p 48875 -e production` 2015-07-26T06:50:30.760680+00:00 app[web.1]: => Booting Puma 2015-07-26T06:50:30.760714+00:00 app[web.1]: => Rails 4.2.1 application starting in production on http://0.0.0.0:48875 2015-07-26T06:50:30.760716+00:00 app[web.1]: => Run `rails server -h` for more startup options 2015-07-26T06:50:30.760718+00:00 app[web.1]: => Ctrl-C to shutdown server 2015-07-26T06:50:31.578843+00:00 app[web.1]: Puma 2.12.2 starting... 2015-07-26T06:50:31.578851+00:00 app[web.1]: * Min threads: 0, max threads: 16 2015-07-26T06:50:31.578859+00:00 app[web.1]: * Environment: production 2015-07-26T06:50:31.578861+00:00 app[web.1]: * Listening on tcp://0.0.0.0:48875 

如果有什么不清楚我会道歉,如果我遗漏了任何东西,我会很乐意提供更多信息。

编辑

以下是/app/assets/javascripts/channels/index.js.erb中的更新代码

 //= require cable //= require_self //= require_tree . this.App = {}; App.cable = Cable.createConsumer(''); 

其中ENV [“CABLE_SERVER”]指向ws://the-action-cable-server.herokuapp.com 。 此变量存储在rails服务器env变量中。

问题

Heroku 路由器有一些限制:它只会侦听端口80和443.换句话说,你无法在任何Heroku应用程序上打开固定端口。 在ActionCable服务器的情况下,无法打开固定端口并将websocket流量路由到它。 因此Heroku允许这样的事情(我怀疑)或者我们使用解决方法。

解决方法

从actioncable的0.0.3版开始,这是我使用的解决方法。

我们的想法是没有一个Heroku应用程序而是两个:一个用于主rails服务器,一个用于ActionCable服务器。 两者都可以在端口80(或443)上运行。

从一个代码库运行两个不同的服务器只需要有两个Procfiles:一个用于rails,一个用于action cable。 有一个buildpack来处理这个问题。 要使用它,您还需要多个buildpack 。

假设你有两个名为railsactioncable Heroku应用程序。

使用.buildpacks命令在项目的根目录中创建.buildpacks文件:

 https://github.com/cantino/heroku-selectable-procfile https://github.com/heroku/heroku-buildpack-ruby 

railsactioncable ,使用https://github.com/heroku/heroku-buildpack-multi.git创建一个env var BUILDPACK_URL

现在对于Procfiles,我选择保留Procfile以便在本地运行所有东西并创建两个自定义的: Procfile.railsProcfile.actioncable

Procfile.rails ,您描述动作电缆服务器之外的所有所需动态,例如:

 web: bundle exec puma -C config/puma/config.rb clockwork: bundle exec clockwork lib/clockwork.rb worker: bundle exec rake jobs:work 

Procfile.actioncable描述操作电缆服务器:

 web: bundle exec puma -p $PORT cable/config.ru 

请注意,我们使用的是web dyno,它将在端口80(或443)上安装动作电缆服务器。

小心您需要将puma配置文件config/puma.rb到自定义位置。 我选择config/puma/config.rbconfig/puma.rb是你在没有任何特定配置文件的情况下启动puma时的默认位置,这是我们在Procfile.actioncable所拥有的。 这可能会导致意外行为(请参阅下面的评论)。

现在,在rails ,使用Procfile.rails创建一个env var PROCFILE_PATH ,并在actioncable创建一个带有Procfile.actioncable的env var Procfile.actioncable

说到env变量, actioncable需要来自rails所有env变量,这些变量是启动actioncable服务器所必需的,如DATABASE_URL或任何凭据。

现在关键的一步是:我们如何将railsactioncable连接在一起? 这可以通过使用相同的 Redis实例来完成。 rails将把消息放在Redis上, actioncable会监听它们并采取相应的行动。 这就是为什么两者都必须针对相同的 Redis实例。 如果你使用Heroku Redis,你只需要在rails actioncable上设置相同的actioncable 。 这是有线服务器cable.yml的配置文件:

 production: &production :url: <%= ENV["REDIS_URL"] %> :timeout: 1 development: &development :url: <%= ENV["REDIS_URL"] %> :timeout: 1 :inline: true test: *development 

最后一步是更改javascript文件,以便我们可以控制Action Cable服务器的位置。 我们可以使用env var来做到这一点。

如有必要,将.js后缀更改为.js.erb

 //= require cable //= require_self //= require_tree . this.App = {}; App.cable = Cable.createConsumer('<%= ENV["CABLE_SERVER"] %>'); 

CABLE_SERVER变量现在可以在本地指向ws://127.0.0.1:28080 ,在rails ,该值将是actioncable的url。

现在,您已准备好在railsactioncable上部署代码。

注意事项/缺点

  • actioncable ,如果您有任何客户端身份validation,则不能使用示例中的 cookies 。 您现在有两个Heroku应用程序,他们无法共享cookie。 我想你仍然可以使用多个子域的cookie来解决这个问题。
  • 您现在有两个要维护的部署目标。
  • 你有多个Procfiles来维护。
  • 希望随着时间的推移,将有一个更容易的解决方法:)

备择方案

  • 我们可以使用相同的服务器使用简单的中间件处理正常的Web流量 websocket流量。 这是怎么回事。
  • 从rails 5 beta2开始,动作电缆服务器现在也可以与主轨道应用程序一起侧面安装 。 拥有两个不同的服务器仍然有意义:您可以单独扩展它们。

心连心