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

痴心易碎 提交于 2019-11-27 11:15:12

问题


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 em-websocket running on EventMachine.

I was wondering if there was a way to "integrate" an EventMachine reactor into Rails? Where do I put the initialization code? Is this the proper way to accomplish this?

I've seen this example that falls back on Sinatra to do an EventMachine GET request, but that isn't quite what I'm looking for.

Any help is appreciated.


回答1:


I'd try using em-synchrony to start a reactor in a fiber. In a rails app you can probably start it in an initializer since it sounds like you just want to leave the reactor running to respond to websocket requests. As suggested by the other answers I think you want to either setup socket communication with your reactor or use one of the asynchronous clients to a data store which both your reactor and rails code can read from and write to to exchange data.

Some of my coworkers put together some examples of starting EM reactors on demand in ruby code to run their tests within EventMachine. I'd try using that as a possible example; raking and testing with eventmachine




回答2:


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.




回答3:


If you run rails application in a thin server (bundle exec thin start) thin server run EventMachine for you and then your rails application can execute EM code wherever you need.

By example:

A library o initializer with that code:

EM.next_tick do
  EM.add_periodic_timer(20) do
    puts 'from Event Machine in rails code'
  end
end

not blocks rails processes application.




回答4:


Don't know if this is what you are after. But if you would like to do provide some kind of socket-messaging system.

Have a look at Faye. It provides message servers for Node.js and Rack. There is also a rails cast for this by Ryan Bates which should simplify the implementation.

Hope that helps.




回答5:


I spent a considerable amount of time looking into this. EventMachine need to run as a thread in your rails install (unless you are using Thin,) and there are some special considerations for Passenger. I wrote our implementation up here: http://www.hiringthing.com/2011/11/04/eventmachine-with-rails.html

UPDATE

We pulled this configuration out into a gem called Momentarily. Source is here https://github.com/eatenbyagrue/momentarily




回答6:


I'd consider looking into Cramp. It's an async framework built on top of EventMachine, and it supports Thin server:

Rack Middlewares support + Rainbows! and Thin web servers




回答7:


You probably shouldn't use EM any more if you can help it, it seems to no longer be maintained - if you encounter a bug - you're on your own.

Most of the answers above don't work in JRuby due to https://github.com/eventmachine/eventmachine/issues/479 - namely the pattern:

Thread.new{ EM.run }

used by EM::Synchrony and various answers found around the internet (such as EventMachine and Ruby Threads - what's really going on here?) are broken under JRuby eventmachine implementation (fibers are threads in jruby and there's currently no roadmap on when this will change).

JRuby messaging options would be

  1. deploy with TorqueBox (which comes bundled with HornetQ), http://torquebox.org/news/2011/08/15/websockets-stomp-and-torquebox/, impressive and enterprisey but not really elegant unless you're coming from a Java background
  2. newer versions of Faye should work with JRuby, Faye in jruby on rails
  3. note for the future, keep an eye on the celluloid community, some interesting distributed solutions are coming from there https://github.com/celluloid/reel/wiki/WebSockets, https://github.com/celluloid/dcell
  4. ?



回答8:


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).



来源:https://stackoverflow.com/questions/5799406/how-do-you-spawn-an-eventmachine-inside-a-rails-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!