How do you spawn an EventMachine "inside" a Rails app? - ruby-on-rails

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.

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.

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.

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.

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

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

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

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
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
newer versions of Faye should work with JRuby, Faye in jruby on rails
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
?

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

Related

Automatic Reloading of Sinatra App mounted inside Rails App

I've run into what I hope is an easy-ish fix for someone more experienced than me when adding a Sinatra app to an existing Rails app.
I currently have a large rails monolith that I am planning to break apart into an SPA backed by a JSON API. Since I will still need to support the monolith until the API is completed I would like to mount the API (written in Sinatra) inside the existing Rails app as I port functionality over with a goal of removing the Rails app itself in a few months. The reason I've mounted the Sinatra app inside Rails instead of setting it up as a separate service was that I wanted easy code sharing between the two as I intend to continue using ActiveRecord as my ORM in Sinatra once the migration is complete.
I've mounted the Sinatra mockup inside the Rails app without any issues using the Rails routes.rb file as:
Rails.application.routes.draw do
mount API::Core, at: '/api'
...
end
I'm not doing any work with config.ru as mounting the API inside the routes.rb file seemed to suit my needs. If I need to put in some more legwork to get this running properly that is not an issue.
The entrypoint for the sinatra app is also fairly simple with just a couple controllers loaded in to segment the routing:
require 'sinatra/base'
require 'sinatra/json'
require_relative 'controllers/first_controller'
require_relative 'controllers/second_controller'
module API
class Core < Sinatra::Base
register Sinatra::FirstControllerApi
register Sinatra::SecondControllerApi
end
end
The problem I'm running into is one I expected with Sinatra but haven't been able to flex my google-fu enough to find a solution. Rails automatically reloads code on each change/request as expected but Sinatra does not. Every time I change controller code in the Sinatra API I need to restart the entire Rails server to serve the new content. Since my dev environment runs in docker containers this can take a while to start up each time and is becoming cumbersome.
Is there a 'canonical' solution to the problem of automagically reloading the Sinatra app mounted inside the Rails app or am I just over-complicating the problem? I know there are some gems for Sinatra that apply to this space but I haven't seen any info in how to get them working in this 'odd' edge case.
Please let me know if you need any more info, hopefully I've provided enough for someone to comprehend my issues.
Just like with a Sinatra app on it's own, a Sinatra app mounted inside o rails will not automatically reload as you make changes. Typically in Sinatra people would use external tools to help solve this problem, so they might set up something like Shotgun to watch the directory and restart the server any time a change has happened.
But, like most things in Rails, there is a way hook into it's functionatly for your own programming benefit.
ActiveSupport::FileUpdateChecker
Rails has a handy ActiveSupport::FileUpdateChecker that can watch a file, or a list of files. When they change it will call back to a block. You can use this to reload the Sinatra app -- or anything else for that matter.
In your case you might want to add the following to config/environments/development.rb in the config block for the application:
Rails.application.configure do
# ...
sinatra_reloader = ActiveSupport::FileUpdateChecker.new(Dir["path/to/sinatra/app/**"]) do
Rails.application.reload_routes!
end
config.to_prepare do
sinatra_reloader.execute_if_updated
end
end
Robert Mosolgo has a good write up on his blog: Watching Files During Rails Development. His approach is a little more thorough, but more complicated.

Puma 2.9.2 and rufus-scheduler 3.0.3 incompatibility

I´m using Rufus Scheduler 3.0.3 in a Ruby on Rails 4.1.4 web app and it´s working great with Unicorn. I moved to Puma and it´s great but I have realized Rufus is not working with Puma (daemonized).
I have read this issue #183 (comment) https://github.com/puma/puma/issues/183#issuecomment-59386038 that is closed for an earlier version, but it´s still not working and not clear to me if there is already a fix for it.
I don´t know if there is a workaround in the meantime.
UPDATE: There are not much logs to display, my rufus scheduler tasks are working when running with Unicorn, but If I change the server to Puma, it doesn´t run any automated task on my laptop. Even there is not any log to show.
I just add my current Rufus scheduler file:
task_scheduler.rb:
begin
require 'rufus-scheduler'
scheduler = Rufus::Scheduler.new
#Secretary responsible for executing events every 60 seconds.
scheduler.every '60s' do
Secretary.executeEvents
end
# Statistics (Owner) calculation every 1 day.
scheduler.every '24h' do
StatisticsCalculator.updateOwnerStatistics
end
end
Am I missing any configuration?
On the Puma side, I just have this config file config/puma/development.rb with only this:
stdout_redirect 'log/puma.stdout.log', 'log/puma.stderr.log', true
I don´t set up any workers, etc...
No, it works.
I packaged this sample project for you:
https://github.com/jmettraux/for_rober
Rufus-scheduler 3.0.3 schedules just fine with Puma 2.9.2 (Ruby 1.9.3 on Debian GNU/Linux).
Thanks for not blaming other people's work without facts.
If there really is an issue, I suggest you go and read http://www.chiark.greenend.org.uk/~sgtatham/bugs.html, then read it again, three times. It's most surely available in your native language. Then, if you really think rufus-scheduler is the culprit, go and open a detailed issue report at https://github.com/jmettraux/rufus-scheduler/issues Beware posting crappy "it doesn't work" material, it'll earn you only negative reactions.
UPDATE:
I strongly suggest you clone my mini-project on your machine and try it, then report the results here in the comments. The details are in the README.md of the project.
UPDATE:
Roberto is trying to get this issue solved in parallel, directly at https://github.com/puma/puma/issues/607
Finally, it looks there was an small issue. It has been kindly fixed by the Puma guys.
Please, see:
https://github.com/puma/puma/issues/607

Zeus not reloading code changes in model files in Rails

I've recently discovered Zeus and it's fantastic really speeds up my feedback loop when developing it's just that when I'm making changes to my model like adding a new method Zeus doesn't restart and the new method isn't loaded.
I'm not sure where to start debugging but I'm using Rails 4.0.2, ruby 2.0.0p353 and Rspec + Capybara for testing.
Anyone have any ideas or help that would be fantastic.
Thanks a lot
If you are using unicorn this could be your problem. Try using thin instead
Zeus:
Reloads models correctly when modifying callbacks and scopes, which
is not always the case for servers with hot-reload, such as Unicorn.
It also reloads views when writing integration specs.(source)
You may also need to reconfigure foreman. Check this thread for information on foreman support with Zeus: https://github.com/burke/zeus/issues/92

Advice on HTTPS connections using Ruby on Rails

Since I am developing a "secure" OAuth protocol for my RoR3 apps, I need to send protected information over the internet, so I need to use HTTPS connections (SSL/TSL). I read How to Cure Net::HTTP’s Risky Default HTTPS Behavior aticle that mentions the 'always_verify_ssl_certificates' gem, but, since I want to be more "pure" (it means: I do not want to install other gems, but I try to do everything with Ruby on Rails) as possible, I want to do that work without installing new gems.
I read about 'open_uri' (it is also mentioned in the linked article: "open_uri is a common exception - it gets things right!") that is from the Ruby OOPL and I think it can do the same work.
So, for my needs, is 'open_uri' the best choice (although it is more complicated of 'always_verify_ssl_certificates' gem)? If so, can someone help me using that (with an example, if possible) because I have not found good guides about?
You should find the best tool for the job and use it. You should not try to limit your usage of libraries to just Rails and the Ruby standard library, because these two alone will not always provide you with everything you need. As you have indicated, you found the right tool for the job - don't reject it just because it's not part of "official" Ruby or Rails.
You can easily manage which gems your application needs with Bundler, such that everyone on the team is, with a single command, always able to install and run the application, including automatically installing all gem dependencies. Rails 3, by default, integrates with Bundler and expects that you will use Bundler to manage all your gem dependencies.

Viewing a Ruby on Rails script in my native browser

I'm new to developing in Ruby and have mostly been using irb to experiment with code. For longer scripts, it would be helpful to be able to run them in my native browser (similar to how I run php scripts through MAMP). I believe there is a way to do this using localhost:3000 but I have not been able to get it to work. So my question is, what is the best way to view Ruby scripts in my native browser?
Well, running some Ruby code in IRB has nothing to do with using the Rails framework.
Follow a tutorial (for example this one) to learn the Rails framework itself now you have some understanding of the Ruby language.
Good luck.
I don't see how this would really be helpful to you, but it would be pretty easy to put your code into a simple Sinatra route and have that serve the result of the code into a browser if you want. Then you can just…
require 'rubygems'
require 'sinatra'
get '/' do
"Hello World! This is file #{$0} live from Boulder!"
end
And when you access the server on your local computer, it will print whatever you put in the method.
I would be interested to hear why you want to do this rather than IRB, though. This seems like kind of a perverse way to code in most cases.
Rack is a Ruby webserver interface, you probably want to use that to hook your ruby script up with a server.

Resources