How do you spawn an EventMachine “inside” a Rails app?

前端 未结 8 1941
星月不相逢
星月不相逢 2020-12-13 14:54

I\'ve got a Rails application, and am looking to add some sort of WebSocket support to it. From various googling, it appears that the best Ruby based WebSocket solution is

相关标签:
8条回答
  • 2020-12-13 15:40

    You cannot run the Eventmachine engine inside of Rails itself as it is a persistent run loop that would block one of your Rails processes permanently. What is usually done is there's a side-process that uses Eventmachine and Rails communicates with it through sockets to send notifications.

    Juggernaut serves as an example of this kind of thing where it implements a Websocket client and a Rails hook to send notifications to it. The project has since deprecated the Ruby version in favor of a JavaScript Node.js version but this still serves as a very thorough example of how Eventmachine can be used.

    0 讨论(0)
  • 2020-12-13 15:40

    I had same problem and found solution. First, put your code in lib dir (for example /lib/listener/init.rb) and create one class method that run EM, for example Listener.run.

    #!/usr/bin/env ruby
    
    require File.expand_path('../../config/environment', File.dirname(__FILE__))
    
    class Listener
      def self.run
      # your code here
      # you can access your models too
      end
    end
    

    After that I used dante gem. Create /init/listener file. The code may be like that:

    #!/usr/bin/env ruby
    
    require File.expand_path('../../lib/listener/init.rb', __FILE__)
    
    log_file = File.expand_path('../../log/listener.stdout.log', __FILE__)
    pid_file = File.expand_path('../../tmp/listener.pid', __FILE__)
    
    listener = Dante::Runner.new('listener')
    
    if ARGV[0] === 'start'
      listener.execute(daemonize: true,
                       pid_path: pid_file,
                       log_path: log_file) { Listener.run }
    elsif ARGV[0] === 'restart'
      listener.execute(daemonize: true,
                       restart: true,
                       pid_path: pid_file,
                       log_path: log_file) { Listener.run }
    elsif ARGV[0] === 'stop'
      listener.execute(kill: true, pid_path: pid_file)
    end
    

    Now you can run you code like that: ./bin/listener start, ./bin/listener restart, ./bin/listener stop

    You can use god for monitoring your listener is running. But make sure you're using same pid file (/tmp/listener.pid).

    0 讨论(0)
提交回复
热议问题