1. 介绍

    之前我们说过,有两种方式可以运行在rails应用中运行websocket,一种是以rack hijack的方式嵌入到rails应用中,以路由的形式挂载,成为rails应用的一部分,这种方式的话,就不用另开一个进程,因为它是rails应用的一部分,而还有另一种式,就是以Standalone的方式,另开一个独立于web进程的websocket进程,这个进程是专门处理websocket连接和请求的,这样的话就把web和websocket进程分开了。
    而今天我们要讲的是websocket的部署。
    这个部署分为两部分,第一部分是websocket的进程的部署,另一部分是nginx的配置。
    如果websocket是以rack hijack方式运行,就不用考虑进程的部署,只有当websocket是以Standalone方式运行的时候才要把那个进程部署起来,然而,不管是什么方式,nginx的配置都是需要的。

    1. 使用

    当websocket是以Standalone方式运行时,在测试端是以下面的方式运行的。

    1. bundle exec puma -p 28080 cable/config.ru

    也就是说,我们要把这个指令产生的效果和nginx结合搬到服务器主机上。而且我们在每次部署自动控制这个服务器的重启。
    首先还是得先部署puma的服务,再来处理nginx。
    2.1 mina-puma的改造

    刚开始会尝试使用mina-puma。
    你会发现这个过程是失败的。虽说mina-puma也是puma结合pumactl的指令来控制puma的启动,重启等。
    但是查看下mina-puma就会知道,它也没像上面那样使用端口,也没有指令配置文件。
    所以我们需要结合我们自己的条件来改造。
    在config/deploy.rb文件中添加下面的内容。

    1. set :puma_cmd, -> { "#{bundle_prefix} puma" }
    2. set :puma_pid, -> { "#{deploy_to}/#{shared_path}/pids/puma.pid" }
    3. set :puma_state, -> { "#{deploy_to}/#{shared_path}/pids/puma.state" }
    4. set :pumactl_cmd, -> { "#{bundle_prefix} pumactl" }
    5. set :puma_env, -> { fetch(:rails_env, 'production') }
    6. set :pumactl_socket, -> { "#{deploy_to}/#{shared_path}/tmp/sockets/pumactl.sock" }
    7. set :puma_socket, -> { "#{deploy_to}/#{shared_path}/tmp/sockets/puma.sock" }
    8. desc 'Start puma'
    9. task :puma_start => :environment do
    10. queue! %[
    11. if [ -e '#{pumactl_socket}' ]; then
    12. echo 'Puma is already running!';
    13. else
    14. cd #{deploy_to}/#{current_path} && #{puma_cmd} -q -d -e #{puma_env} -b 'unix://#{puma_socket}' -S #{puma_state} --pidfile #{puma_pid} --control 'unix://#{pumactl_socket}' #{deploy_to}/#{current_path}/cable/config.ru
    15. fi
    16. ]
    17. end
    18. desc 'Stop puma'
    19. task :puma_stop => :environment do
    20. queue! %[
    21. if [ -e '#{pumactl_socket}' ]; then
    22. echo 'Puma is stopping!'
    23. cd #{deploy_to}/#{current_path} && #{pumactl_cmd} -S #{puma_state} stop
    24. rm -f '#{pumactl_socket}'
    25. else
    26. echo 'Puma is not running!';
    27. fi
    28. ]
    29. end
    30. desc 'Restart puma'
    31. task puma_restart: :environment do
    32. invoke :'puma_stop'
    33. invoke :'puma_start'
    34. end

    也可以把这些内容封装成文件放到lib目录,再来require,不过这不重要。
    在mina部署重启用应的地方引用就好了。

    1. desc "Deploys the current version to the server."
    2. task :deploy => :environment do
    3. deploy do
    4. invoke :'sidekiq:quiet'
    5. ...
    6. to :launch do
    7. ...
    8. invoke :'puma_restart'
    9. ...
    10. end
    11. end
    12. end

    上面的代码显示,还是用unix socket来监听,而不用端口。所以接下来,对nginx的配置还是跟前面部署unicorn差不多,只是多了websocket的部分。
    2.2 nginx

    nginx中的配置文件是这样的。

    1. upstream tt {
    2. server unix:/tmp/unicorn_production.sock fail_timeout=0;
    3. }
    4. upstream ws {
    5. server unix:///home/eason/tt_deploy/shared/tmp/sockets/puma.sock fail_timeout=0;
    6. }
    7. server {
    8. server_name www.rails365.net;
    9. root /home/eason/tt_deploy/current/public;
    10. try_files $uri/index.html $uri @tt;
    11. location @tt {
    12. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    13. proxy_set_header Host $http_host;
    14. proxy_redirect off;
    15. proxy_pass http://tt;
    16. }
    17. location /ws/ {
    18. proxy_pass http://ws;
    19. proxy_http_version 1.1;
    20. proxy_set_header Upgrade $http_upgrade;
    21. proxy_set_header Connection "upgrade";
    22. }
    23. ...
    24. }

    不重要的部分被我省略了,最重要的是location /ws/这部分。其实就多了三行关于websocket的配置,很简单。
    要测试是否配置成功。可以有两种简单的方法。
    第一种是用chrome的开发者工具中的network部分查看是否有101状态码的请求。
    第二种是在chrome的console里测试,比如new WebSocket(‘ws://www.rails365.net/ws’);,如果没报错,返回正常 ,一般就没问题的。有一点需要注意,假如用的是https,ws就得改成wss。
    完结。