Flauwekeul
Flauwekeul

Reputation: 1009

Running EventMachine in new Thread after Rails is loaded using Thin

I have a Rails 3.2 app running on a Thin server and in application.rb I want to start EventMachine:

# application.rb

config.after_initialize do
  if ENV['EM']
    EM.run do
      host = '0.0.0.0'
      port = 3001

      # hit Ctrl + C to stop
      Signal.trap("INT")  { EventMachine.stop }
      Signal.trap("TERM") { EventMachine.stop }

      EventMachine::start_server host, port, SomeModule

      puts "EventMachine running on #{host}:#{port}. Ctrl + C to stop."
    end
  end
end

SomeModule has code that depends on Rails being loaded. That's why I put this in the after_initialize block instead of in an initializer.

Now when I start my server (with rails s) my output looks fine:

=> Booting Thin
=> Rails 3.2.13 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
EventMachine running on 0.0.0.0:3001. Ctrl + C to stop.

But when I go to localhost in my browser I get a 204 No Content response.

I can think of several things that causes this, but not a solution :)

Upvotes: 0

Views: 2015

Answers (2)

Flauwekeul
Flauwekeul

Reputation: 1009

After some more Googling I found that since I'm using Thin I don't need to run another EventMachine.

My after_initialize block now looks like this:

config.after_initialize do
  include SomeModule
end

And in SomeModule I wrapped my code in an EM.next_tick block or I'd get a "eventmachine not initialized: evma_connect_to_server (RuntimeError)" error.

Using EventMachine in a Rails app with Thin was way easier than I thought :)

Upvotes: 3

Spajus
Spajus

Reputation: 7406

You should prevent autoloading your ruby code that invokes EventMachine, otherwise it will block your main thread. Put your script to lib/daemons, then create a startup script for your EventMachine and use it as a daemon. I.e.:

#!/usr/bin/env ruby
# this is: ./scripts/my_daemon

require 'daemons'

options = {
  multiple: false,
  backtrace: true,
  app_name: 'my_daemon',
  dir_mode: :normal,
  dir: '/tmp/my_daemon',
  log_dir: '/tmp/my_daemon',
  log_output: true,
  ARGV: ARGV,
}

system "mkdir -p /tmp/my_daemons"
Daemons.run(File.join(File.dirname(__FILE__), '../lib/daemons/my_daemon.rb'), options)

You'll need to add 'daemons' gem to your Gemfile.

Then just run script/my_daemon start from rails root. There are more commands:

  • script/my_daemon stop # stops the daemon
  • script/my_daemon run # runs in foreground, so you can see the output and debug it
  • script/my_daemon status # shows if anything is running

You'll find logs in /tmp/my_daemons/my_daemon.output

Find more about daemons here: http://daemons.rubyforge.org/Daemons.html

Upvotes: 0

Related Questions