Запуск EventMachine в новом потоке после загрузки Rails с использованием Thin

У меня есть приложение Rails 3.2, работающее на тонком сервере, и в application.rb я хочу запустить 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 зависит от загрузки Rails. Вот почему я поместил это в блок after_initialize, а не в инициализатор.

Теперь, когда я запускаю свой сервер (с rails s), мой вывод выглядит нормально:

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

Но когда я захожу на локальный хост в своем браузере, я получаю ответ 204 No Content.

Я могу думать о нескольких вещах, которые вызывают это, но не о решении :)

  • Возможно, я запускаю EventMachine в том же потоке, что и приложение Rails. Но Тонкий должен справиться с этим правильно?
  • Может быть, мне следует запустить свой сервер по-другому, но как тогда?

person Flauwekeul    schedule 19.05.2013    source источник


Ответы (2)


После еще нескольких поисков в Google я обнаружил, что, поскольку я использую Thin, мне не нужно запускать еще один EventMachine.

Мой блок after_initialize теперь выглядит так:

config.after_initialize do
  include SomeModule
end

И в SomeModule я завернул свой код в блок EM.next_tick, иначе я получил бы ошибку «eventmachine not initialized: evma_connect_to_server (RuntimeError)».

Использование EventMachine в приложении Rails с Thin оказалось намного проще, чем я думал :)

person Flauwekeul    schedule 19.05.2013
comment
дополнительная информация о EventMachine github вики - person thinkOfaNumber; 22.10.2013

Вы должны предотвратить автоматическую загрузку вашего рубинового кода, который вызывает EventMachine, иначе он заблокирует ваш основной поток. Поместите свой сценарий в lib/daemons, затем создайте сценарий запуска для EventMachine и используйте его в качестве демона. То есть:

#!/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)

Вам нужно будет добавить гем «daemons» в ваш Gemfile.

Затем просто запустите script/my_daemon start из корня рельсов. Есть еще команды:

  • script/my_daemon stop # останавливает демон
  • script/my_daemon run # выполняется на переднем плане, чтобы вы могли видеть вывод и отлаживать его
  • script/my_daemon status # показывает, запущено ли что-нибудь

Вы найдете журналы в /tmp/my_daemons/my_daemon.output

Узнайте больше о демонах здесь: http://daemons.rubyforge.org/Daemons.html

person Spajus    schedule 19.05.2013
comment
Тем временем я нашел решение. Нужен ли мне демон, если я использую Thin? - person Flauwekeul; 19.05.2013
comment
Это зависит от того, какую проблему вы решаете. Daemons gem дает вам больше контроля над вашими фоновыми процессами, он отделит EventMachine от вашего основного приложения, вы сможете запускать/останавливать его независимо. И вы можете включить config/environment.rb, чтобы получить полную среду вашего приложения Rails в вашем демоне. Но поскольку вы нашли более простое решение, оно может сработать для вас. :) - person Spajus; 19.05.2013
comment
Это звучит как то, что мне может понадобиться в будущем, и я обязательно изучу это. Спасибо! - person Flauwekeul; 19.05.2013