使用 Action Cable 将 Rails 应用上的 Ruby 部署到 Heroku(Puma 端口侦听)
Deploying Ruby on Rails app to Heroku while using Action Cable (Puma port listening)
我已经让 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"] %>');
其中 ENV["CABLE_SERVER"] 指向 ws://the-action-cable-server.herokuapp.com
。此变量存储在 rails 服务器环境变量中。
问题
Heroku 有一些限制router:它只会监听端口 80 和 443。换句话说,您不能在任何 Heroku 应用程序上打开固定端口。在 ActionCable 服务器案例中,无法打开固定端口并将 websocket 流量路由到它。因此,要么 Heroku 允许这样的事情(我对此表示怀疑),要么我们使用解决方法。
解决方法
从 actioncable 的 0.0.3 版开始,这是我使用的解决方法。
我们的想法是拥有两个 Heroku 应用程序而不是一个:一个用于主 rails 服务器,一个用于 ActionCable 服务器。两者都会 运行 在端口 80(或 443)上。
从一个代码库到 运行 两个不同的服务器只需要有两个 Procfile:一个用于 rails,一个用于动作电缆。有个buildpack to handle this. To use it, you also need the multi buildpack.
假设您有两个名为 rails
和 actioncable
的 Heroku 应用程序。
在项目的根目录中创建一个 .buildpacks
文件:
https://github.com/cantino/heroku-selectable-procfile
https://github.com/heroku/heroku-buildpack-ruby
在 rails
和 actioncable
上,使用 https://github.com/heroku/heroku-buildpack-multi.git
创建一个环境变量 BUILDPACK_URL
现在对于 Procfiles,我选择保留 Procfile
以便 运行 在本地与工头一起创建两个自定义文件:Procfile.rails
和 Procfile.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)上安装 action cable 服务器。
注意 您需要将 puma 配置文件 config/puma.rb
移动到自定义位置。我选择config/puma/config.rb
。 config/puma.rb
是启动 puma 时没有任何特定配置文件的默认位置,这是我们在 Procfile.actioncable
中的内容。这可能会导致意外行为(请参阅下面的评论)。
现在,在 rails
上,用 Procfile.rails
创建一个环境变量 PROCFILE_PATH
,在 actioncable
上,用 [=24 创建一个环境变量 PROCFILE_PATH
=].
说到环境变量,actioncable
需要来自 rails
的所有环境变量,这些环境变量是启动 actioncable 服务器所必需的,例如 DATABASE_URL 或任何凭据。
现在是关键步骤:我们如何将 rails
和 actioncable
连接在一起?这只需使用 same Redis 实例即可完成。 rails
将把消息放在 Redis 上,actioncable
将听取它们并采取相应的行动。这就是为什么两者都必须针对 相同的 Redis 实例。如果你使用 Heroku Redis,你只需要在 rails
和 actioncable
上设置相同的值 REDIS_URL
。这是有线服务器的配置文件 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 服务器的位置。我们可以通过使用环境变量来做到这一点。
如有必要,将 .js
后缀更改为 .js.erb
。
//= require cable
//= require_self
//= require_tree .
this.App = {};
App.cable = Cable.createConsumer('<%= ENV["CABLE_SERVER"] %>');
这个 CABLE_SERVER
变量现在可以在本地和 rails
上指向 ws://127.0.0.1:28080
,该值将是 actioncable
的 url。
现在您已准备好在 rails
和 actioncable
上部署代码。
Caveats/Drawbacks
- 在
actioncable
上,如果您有任何客户端身份验证,则不能像在 examples. You have now two Heroku apps and they can't share a cookie. I guess you can still workaround 中那样使用多个子域的 cookie 中的 cookies
。
- 您现在有两个部署目标需要维护。
- 您有多个 Procfile 需要维护。
- 希望随着时间的推移,会有更简单的解决方法:)
备选方案
- 我们可以使用一个简单的中间件让同一台服务器处理正常的 Web 流量 和 websocket 流量。 Here就是这样。
- 从 rails 5 beta2 开始,动作电缆服务器现在也可以 side-mounted 与您的主要 rails 应用程序一起使用。拥有两台不同的服务器仍然有意义:您可以单独扩展它们。
hth
我已经让 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"] %>');
其中 ENV["CABLE_SERVER"] 指向 ws://the-action-cable-server.herokuapp.com
。此变量存储在 rails 服务器环境变量中。
问题
Heroku 有一些限制router:它只会监听端口 80 和 443。换句话说,您不能在任何 Heroku 应用程序上打开固定端口。在 ActionCable 服务器案例中,无法打开固定端口并将 websocket 流量路由到它。因此,要么 Heroku 允许这样的事情(我对此表示怀疑),要么我们使用解决方法。
解决方法
从 actioncable 的 0.0.3 版开始,这是我使用的解决方法。
我们的想法是拥有两个 Heroku 应用程序而不是一个:一个用于主 rails 服务器,一个用于 ActionCable 服务器。两者都会 运行 在端口 80(或 443)上。
从一个代码库到 运行 两个不同的服务器只需要有两个 Procfile:一个用于 rails,一个用于动作电缆。有个buildpack to handle this. To use it, you also need the multi buildpack.
假设您有两个名为 rails
和 actioncable
的 Heroku 应用程序。
在项目的根目录中创建一个 .buildpacks
文件:
https://github.com/cantino/heroku-selectable-procfile
https://github.com/heroku/heroku-buildpack-ruby
在 rails
和 actioncable
上,使用 https://github.com/heroku/heroku-buildpack-multi.git
BUILDPACK_URL
现在对于 Procfiles,我选择保留 Procfile
以便 运行 在本地与工头一起创建两个自定义文件:Procfile.rails
和 Procfile.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)上安装 action cable 服务器。
注意 您需要将 puma 配置文件 config/puma.rb
移动到自定义位置。我选择config/puma/config.rb
。 config/puma.rb
是启动 puma 时没有任何特定配置文件的默认位置,这是我们在 Procfile.actioncable
中的内容。这可能会导致意外行为(请参阅下面的评论)。
现在,在 rails
上,用 Procfile.rails
创建一个环境变量 PROCFILE_PATH
,在 actioncable
上,用 [=24 创建一个环境变量 PROCFILE_PATH
=].
说到环境变量,actioncable
需要来自 rails
的所有环境变量,这些环境变量是启动 actioncable 服务器所必需的,例如 DATABASE_URL 或任何凭据。
现在是关键步骤:我们如何将 rails
和 actioncable
连接在一起?这只需使用 same Redis 实例即可完成。 rails
将把消息放在 Redis 上,actioncable
将听取它们并采取相应的行动。这就是为什么两者都必须针对 相同的 Redis 实例。如果你使用 Heroku Redis,你只需要在 rails
和 actioncable
上设置相同的值 REDIS_URL
。这是有线服务器的配置文件 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 服务器的位置。我们可以通过使用环境变量来做到这一点。
如有必要,将 .js
后缀更改为 .js.erb
。
//= require cable
//= require_self
//= require_tree .
this.App = {};
App.cable = Cable.createConsumer('<%= ENV["CABLE_SERVER"] %>');
这个 CABLE_SERVER
变量现在可以在本地和 rails
上指向 ws://127.0.0.1:28080
,该值将是 actioncable
的 url。
现在您已准备好在 rails
和 actioncable
上部署代码。
Caveats/Drawbacks
- 在
actioncable
上,如果您有任何客户端身份验证,则不能像在 examples. You have now two Heroku apps and they can't share a cookie. I guess you can still workaround 中那样使用多个子域的 cookie 中的cookies
。 - 您现在有两个部署目标需要维护。
- 您有多个 Procfile 需要维护。
- 希望随着时间的推移,会有更简单的解决方法:)
备选方案
- 我们可以使用一个简单的中间件让同一台服务器处理正常的 Web 流量 和 websocket 流量。 Here就是这样。
- 从 rails 5 beta2 开始,动作电缆服务器现在也可以 side-mounted 与您的主要 rails 应用程序一起使用。拥有两台不同的服务器仍然有意义:您可以单独扩展它们。
hth