02 августа 2009

способы запуска Camping приложений

Недавно ради интереса посчитал - после моих экспериментов над Camping приложением его можно запустить 4 способами:
  • традиционным camping app.rb
  • напрямую app.rb или ruby app.rb
  • через Passenger
  • с использованием библиотеки Daemons
Первый не требует никаких дополнительных действий и использует все традиционные умолчания, этим и удобен.
Второй требует, чтобы приложение само себя запустило, примерно таким кодом:
if __FILE__ == $0 || !ENV['RACK_ENV'].nil?
  App::Models::Base.establish_connection :adapter => 'sqlite3', \
    :database => "#{File.expand_path(File.dirname(__FILE__))}/../app.db"
  App.create
end
if __FILE__ == $0
  require 'mongrel/camping'
  server = Mongrel::Camping::start(OPTIONS[:app_host], OPTIONS[:app_port], '/', App)
  trap("INT"){server.stop;exit}
  trap("KILL"){server.stop;exit}
  $logger.info "Apnp server running at http://#{OPTIONS[:app_host]}:#{OPTIONS[:app_port]}"
  server.acceptor.join
end
Первый условный блок общий для данного метода и запуска из-под Passenger. Полезно, если требуется запустить как-то нестандартно - с другим адаптером БД etc. Есть один неприятный момент - этот метод работает только с 1.5 версией Camping, так что если используется Git-версия(1.9) - то стоит или ставить обычным gem install camping или использовать другой способ запуска (судя по экспериментам, для 1.9 работает только первый).
Третий способ тоже требует создания AR подключения и запуска приложения. Запуск из-под Passenger обнаруживается по наличию переменной окружения RACK_ENV. Об использовании этой переменной немного ниже. Ну а config.ru выглядит так:
# vim:syntax=ruby
require 'rubygems'
require 'rack'
$: << File.expand_path(File.dirname(__FILE__))
require 'bin/app'
run Rack::Adapter::Camping.new(App)
Самый, на мой взгляд, удобный способ со многими преимуществами: легко перезапускать приложение (да, уже не автоматически, как в первом), ну и все возможности апача на руках. С автоматическим перезапуском поможет vim:
" restart Passenger app
au BufWritePost * silent !test -f 'tmp/restart.txt' && touch 'tmp/restart.txt'
Четвёртый способ заключается в написании небольшого враппера вокруг приложения, который запускает его вторым способом, но в фоне:
#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
Daemons.run( File.expand_path(File.dirname(__FILE__))+'/app.rb')
Однако на практике, имхо, это проблем создаёт больше, чем преимуществ, и ради демонизации приложения можно использовать того же пассажира.
Ну и напоследок об окружениях. Идея RAILS_ENV хороша, почему бы и тут не сделать так же.
DEVELOPMENT = ENV['RACK_ENV'].nil? || ENV['RACK_ENV'] == 'development' # some things are for development purposes only
$logger = ((ENV['RACK_ENV'] || defined? Daemons )? \
           # file-based logger for background execution and stdout for the rest
           Logger.new("#{File.expand_path(File.dirname(__FILE__))}/../log/app.log", 10, 1024000) : \
           Logger.new(STDOUT))
Так, у меня в development окружении поставлены в некоторых местах задержки для тестирования клиента этого приложения, а для всех фоновых способов запуска логи пишутся в файл вместо стандартного вывода. При желании, раз уж нам бесплатно досталась в руки RACK_ENV, то можно делать подключения к разным базам и писать логи в разные файлы в зависимости от неё.

Комментариев нет: