Turn a ruby script into an always running job - ruby-on-rails

I have created a program that I need to run constantly. It currently lives at scripts/mailman. I start it by doing this:
sudo bundle exec rails runner script/mailman &
It seams to stop after I logout of the server. Here is the contents of my mailman program:
#!/usr/bin/env ruby
require "rubygems"
require "bundler/setup"
require "mailman"
require "rb-inotify"
Mailman.config.logger = Logger.new("/var/log/mailman.log")
Mailman.config.maildir = '/var/mail'
require File.dirname(__FILE__) + "/../../config/application"
Rails.application.require_environment!
Mailman::Application.run do
default do
begin
Bin.receive_mail(message)
end
end
end
What is a good way to start this program automatically and keep it running always? I am running this on Ubuntu.

Use the 'daemons' gem as suggested here:
Make a Ruby program a daemon?
Seems also to be very popular on RubyToolbox
https://www.ruby-toolbox.com/categories/daemonizing

I've found that the daemons gem works well for this.
Assuming your posted code lives in script/mailman.rb, you can make a file script/mailman_ctl:
#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
Daemons.run('mailman.rb')
I typically give the options {:backtrace => true, :monitor => true} to the Daemons.run call, so that I have a better idea of what happened if the process ever dies.

Related

Is require ´bundler/setup' the same as running Bundler.setup?

Is this:
require 'bundler'
Bundler.setup
accomplishing the same as:
require 'bundler/setup'
As far as I understand, bundler/setup requires all groups automatically, while this isn't the case with require 'bundler'. So considering this fact, does that mean the above 2 snippets of code accomplish the same thing?
The answer is found in the source code of bundler/setup:
require 'bundler/shared_helpers'
if Bundler::SharedHelpers.in_bundle?
require 'bundler'
if STDOUT.tty?
begin
Bundler.setup
rescue Bundler::BundlerError => e
...
end
else
Bundler.setup
end
...
end
The method in_bundle? seems to be checking if Bundler is being run inside itself (for testing purposes, as far as I could make out), and to verify that Gemfile exists.
So yes, for general use, both of your pieces of code are equivalent.
The advantage of the bundler/setup version, is that you can run Ruby from the command line like this:
ruby -rbundler/setup ... some_ruby_script.rb
Which will automatically make your script run under Bundler, even if the script itself might not be Bundler-aware, which is pretty much the same as what bundle exec does too.

Run rb-fsevent in the background

I'm trying to use the Daemons gem to daemonize a process in the background.This process just checks for any change in a directory and reports it. I've used the Daemons gem before and never really ran into any problems, however when I mix it with the rb-fsevent directory monitoring, something seems to go wrong.
Here's the ruby code that monitors the directory change,
require 'rb-fsevent'
require 'rubygems'
notifier = FSEvent.new
notifier.watch "/Test/NewFolder" do |directories|
puts "Detected change inside: #{directories.inspect}"
end
notifier.run
And here's how I'm calling the ruby file,
require 'rubygems'
require 'daemons'
Daemons.run('folder_watcher_mac.rb')
When I run "ruby start_watcher.rb start" nothing is happening. Is this the right way to daemonize the rb-fsevent?

Is there a way Rails 3.0.x can default to using Thin?

I run the Thin webserver for basically every app in my dev/test environments. When I used Mongrel with Rails 2.x, all I had to type was script/server to get it to run the webserver I choose. But with Rails 3, I have to specify Thin every time. Is there a way to get Thin running on my Rails apps by just typing rails s instead of rails s thin?
Yeah it's possible to do this.
The way the rails s command works at the end of the day is by falling through to Rack and letting it pick the server. By default the Rack handler will try to use mongrel and if it can't find mongrel it will go with webrick. All we have to do is patch the handler slightly. We'll need to insert our patch into the rails script itself. Here is what you do, crack open your script/rails file. By default it should look like this:
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
require 'rails/commands'
We insert our patch right before the require 'rails/commands' line. Our new file should look like this:
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
require 'rack/handler'
Rack::Handler.class_eval do
def self.default(options = {})
# Guess.
if ENV.include?("PHP_FCGI_CHILDREN")
# We already speak FastCGI
options.delete :File
options.delete :Port
Rack::Handler::FastCGI
elsif ENV.include?("REQUEST_METHOD")
Rack::Handler::CGI
else
begin
Rack::Handler::Mongrel
rescue LoadError
begin
Rack::Handler::Thin
rescue LoadError
Rack::Handler::WEBrick
end
end
end
end
end
require 'rails/commands'
Notice that it will now try Mongrel and if there is an error try for Thin and only then go with Webrick. Now when you type rails s we get the behaviour we're after.
As of Rails 3.2rc2, thin is now run by default on invoking rails server when gem 'thin' is in your Gemfile! Thanks to this pull request: https://github.com/rack/rack/commit/b487f02b13f42c5933aa42193ed4e1c0b90382d7
Works great for me.
In script/rails the following works as well:
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
require 'rack/handler'
Rack::Handler::WEBrick = Rack::Handler::Thin
require 'rails/commands'
Simply install thin, cd to the directory that your app is in and run thin start. Works perfectly here. :)
You can use http://www.softiesonrails.com/2008/4/27/using-thin-instead-of-mongrel to change as needed. (Its the one I used)

Custom Daemon with Rails 3

I'm trying to create a custom daemon that loads up the Rails environment.
My environment is as follows:
ruby-1.9.2-p180
rails 3.0.5
I did the following:
-Installed the daemons gem
-Installed daemon_generator plugin found here:
https://github.com/dougal/daemon_generator
-Generated a daemon: rails generate daemon listener
All this worked fine. When I run the daemon, it works.
However, as soon as I try to access an active record object like trying to retrieve a user, it blows up.
*** below you find the most recent exception thrown, this will be likely (but not certainly) the exception that made the application exit abnormally ***
#<NameError: method `recognize' not defined in Rack::Mount::RouteSet>
*** below you find all exception objects found in memory, some of them may have been thrown in your application, others may just be in memory because they are standard exceptions ***
#<NoMemoryError: failed to allocate memory>
#<SystemStackError: stack level too deep>
#<fatal: exception reentered>
#<NoMethodError: undefined method `eq' for nil:NilClass>
#<NameError: method `recognize' not defined in Rack::Mount::RouteSet>
Any thoughts on how to create a Daemon that loads up Rails 3.0.5?
I prefer to roll my own rails daemon controllers. Here is a simple example that works for most cases:
script/daemon
#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
ENV["APP_ROOT"] ||= File.expand_path("#{File.dirname(__FILE__)}/..")
ENV["RAILS_ENV_PATH"] ||= "#{ENV["APP_ROOT"]}/config/environment.rb"
script = "#{ENV["APP_ROOT"]}/daemons/#{ARGV[1]}"
Daemons.run(script, dir_mode: :normal, dir: "#{ENV["APP_ROOT"]}/tmp/pids")
daemons/your_daemon_script.rb
require ENV["RAILS_ENV_PATH"]
loop {
... your code ...
}
You can control your deamons by using the following commands:
script/daemon run your_daemon_script.rb
script/daemon start your_daemon_script.rb
script/daemon stop your_daemon_script.rb
This enables me to easily add new daemons and I can easily load rails in each script if necessary.
I had a lot of problems trying get daemon_generator working. I got my daemon working by skipping the daemon_generator all together and just using the daemons gem (v1.1.3).
in urserver_control.rb (in root ruby app directory):
#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
require 'TweetMsg'
Daemons.run('urserver.rb')
in urserver.rb:
#!/usr/bin/env ruby
require File.expand_path(File.join(File.dirname(__FILE__), 'config', 'environmen
t'))
require "rubygems"
--- insert your code here ---
You can test by running your server directly ruby urserver.rb or ruby urserver_controller run
And then once that is working starting and stopping the controllerruby urserver_control.rb {start | stop | run }
Looking at the code in https://github.com/dougal/daemon_generator/blob/master/lib/generators/daemon/templates/script.rb it appears they load things in the wrong order...
Looking at my delayed_job daemon script and config.ru they load config/environment.rb (which in turn loads application.rb and initializes the app)
So a possible fix would be to edit the generated script and make it only require 'config/environment.rb'
I tried this:
#!/usr/bin/env ruby
# You might want to change this
ENV["RAILS_ENV"] ||= "development"
require File.dirname(__FILE__) + "/../config/environment"
$running = true
Signal.trap("TERM") do
$running = false
end
while($running) do
# Replace this with your code
Rails.logger.auto_flushing = true
o = Order.last
Rails.logger.info "The latest order is #{o.id}"
sleep 10
end
and it yielded no errors... (Tried both Rails 3.0.3 and 3.0.5)
I had problems running daemon as is on my staging server (Rails 3.0.7, ruby 1.8.7, passenger 3.0.0). Neither
require File.dirname(FILE) + "/../../config/application"
Rails.application.require_environment!
nor
require File.dirname(FILE) + "/../config/environment"
Worked.
I fixed it by re-installing the standard config.ru in rails root (which I had de-installed to integrate w passenger... not sure now how I will get daemons & passenger to work together now ...)

Rails tests can't find test_helper

I'm trying to run individual tests through ruby test/unit/mytest.rb, but I always get a "no such file to load - test_helper" error. Google brought up a few suggestions, but none of them worked for me. I'm running Rails 3.0, Ruby 1.9.2 (through RVM) on Ubuntu 10.10
Here's what I've tried so far - any suggestions really appreciated
Changed the "require test_helper" to "require File.dirname(FILE) + "/../test_helper"
" in test/unit/mytest_test.rb. It brings back " no such file to load -- test/unit/../test_helper"
Tried running rvm test/unit/mytest_test.rb Same as above
Tried running ruby -I test/unit/mytest_test.rb. No messages to the terminal. After about 5 minutes waiting for something to happen, ctrl+c'd out of it
Any suggestions very appreciated - I'm stumped.
ruby 1.9.2 removed ".", the current directory, from the load path. I have to do this to get it to work:
require 'test_helper'
and call it like:
ruby -I. unit/person_test.rb
I was fighting this thing myself today and i dislike the big require with whole path to file and stuff...
In my case it was fault of Rakefile..
so now it looks like this:
require "bundler/gem_tasks"
require "rake/testtask"
Rake::TestTask.new do |t|
t.libs << "lib"
t.libs << "test" # here is the test_helper
t.pattern = "test/**/*_test.rb"
end
task default: :test
I know its old and has answer marked accepted, but maybe this will also help someone :)
have a nice day
I've added the following to the top of my test files.
require File.expand_path("../../test_helper", __FILE__)
This restores the previous behavior and allows the call to be simply:
ruby test/unit/person_test.rb
Maybe you should run your test cases in this way:
$ rake test
There is no need to change the "require" statement from generated code if you use rake.
Tested with Ruby 1.9.3 and Rails 3.2.8
If you are creating a gem or engine, running rake test in the test dummy application directory will cause this error. Running rake test in the root of the gem will avoid this.
Rails 1.9 no longer includes the current directory in the LOAD_PATH, which causes this problem. You have a few options.
call the test with the -I option from the app dir:
ruby -I test test/functional/test_foo.rb
and use a require with no path:
require "test_helper.rb"
use a full path in the require.  Either
require 'pathname'
require Pathname.new(FILE).realpath.dirname.join('/../test_helper.rb')
or
require (File.dirname(File.realdirpath(__FILE__)) + '/../test_helper.rb')

Resources