Gem Daemons - How to run several different daemons - ruby

Basically I just want to run several daemons in my ruby script :
require 'daemons'
Daemons.run path_1, { :ARGV => ['start'], :app_name => 'app1', :multiple => true, ... }
Daemons.run path_2, { :ARGV => ['start'], :app_name => 'app2', :multiple => true, ... }
But the second Daemons.run is never called when ARGV[0] == 'start' (works perfectly with 'status'/'stop'). What is the right way to do it ?

from http://daemons.rubyforge.org
3- Control a bunch of daemons from another application
Layout: you have an application my_app.rb that wants to run a bunch of server tasks as daemon processes.
# this is my_app.rb
require 'rubygems' # if you use RubyGems
require 'daemons'
task1 = Daemons.call(:multiple => true) do
# first server task
loop {
conn = accept_conn()
serve(conn)
}
end
task2 = Daemons.call do
# second server task
loop {
something_different()
}
end
# the parent process continues to run
# we can even control our tasks, for example stop them
task1.stop
task2.stop
exit
does it fit?

Related

Add logs in different directory using daemon in ruby

I am using daemon to wrap my script and has specified logs location into that :
Script looks like this :
#!/usr/local/bin/ruby
require 'rubygems'
require 'daemons'
Daemons.run_proc(
'script_test', # name of daemon
:log_output => true,
:output_logfilename => "script-test.log",
:logfilename => "script-test.log"
) do
exec 'ruby /opt/script-test/script-test.rb'
end
Problem is my logs are storing in same directory where my script is present. I have to add my logs to different directory such as /var/log/script-test and later have to rotate those logs weekly.
Provide me with a solution so that i can store the logs of script in /var/log directory.
Make sure you are using an absolute path instead of a relative path
For example:
:output_logfilename => "/var/log/script-test.log",
:logfilename => "/var/log/script-test.log"
In order to logrotate your logs, (assuming Linux) add the following to your logrotate config to rotate on a weekly basis:
/var/log/script-test.log {
weekly
missingok
compress
notifempty
copytruncate
}
It worked for me with this configuration as :
Daemons.run_proc(
'script-test', # name of daemon
:log_output => true,
:dir_mode => :normal,
:dir => "/var/log",
:output_logfilename => "script-test.log",
:logfilename => "script-test.log"
) do
exec 'ruby /opt/script-test/script-test.rb'
end

Daemons do not get restarted?

I am trying to run the same script in multiple daemons.
myapp.rb looks like this:
loop do
sleep 5
1 / 0 # crash it
end
my myapp_controller.rb:
require 'rubygems'
require 'daemons'
options = {
:log_output => true,
:backtrace => true,
:monitor => true,
:multiple => true,
:log_dir => '/mnt/log/',
:hard_exit => true
}
Daemons.run(File.join(File.dirname(__FILE__), 'myapp.rb'), options)
When I run ruby myapp_controller.rb start several times in a row, it creates that many daemons, as I expect. But, after a while, due to an error in myapp.rb the daemons crash and the monitor restarts just one and not all. So I end up with a single running daemon.
Why? What am I doing wrong?
I was able to reproduce the behavior. It is not anything you are doing wrong; it is the way the daemons gem behaves.
Going through the code for the daemons gem, turns out the :multiple option doesn't work well with the :monitor option.
The :monitor option works only when the daemon is run in single mode.
I have created a bug report on the daemons project page referencing this question as the source.
More info about the reproduction of the issue:
Multiple daemon processes are created when :multiple => true. Each process has its own pid file in the format of <scriptname>.rb<number>.pid.
However, only one monitor process is created (with a single <scriptname>.rb_monitor.pid file.)
Here are the list of processes started when I start the daemon process 3 times:
$ ps -fe | grep my_server
501 1758 1 0 12:25PM ?? 0:00.63 my_server.rb
501 1759 1 0 12:25PM ?? 0:00.43 my_server.rb_monitor
501 1764 1 0 12:25PM ?? 0:00.54 my_server.rb
501 1834 1 0 12:51PM ?? 0:00.31 my_server.rb
The files in the pid/log folder:
$ ls /tmp/daemons-2013-01-25/
my_server.rb.log my_server.rb1.pid my_server.rb_monitor.pid
my_server.rb0.pid my_server.rb2.pid
Until the issue is resolved, you can change your code to something like this:
#myapp_controller.rb
require 'rubygems'
require 'daemons'
number = ARGV.fetch(1)
options = {
:app_name => "daemon-#{number}" # provide app_name
:log_output => true,
:backtrace => true,
:monitor => true,
:multiple => false, # disable multiple option
:log_dir => '/mnt/log/',
:hard_exit => true
}
Daemons.run(File.join(File.dirname(__FILE__), 'myapp.rb'), options)
And then start your daemons with these commands:
ruby myapp_controller.rb start 1
ruby myapp_controller.rb start 2
...
This slightly changes your startup code, but now you will have a monitor process for each of your daemon processes.

Ruby daemons soft stop

This simple daemon (written using ruby daemons gem) prints numbers from 0 up to 9 until I stop the daemon using the stop command line option:
require 'rubygems'
require 'daemons'
options = {
:multiple => false,
:ontop => false,
:backtrace => true,
:log_output => true,
:monitor => false
}
Daemons.run_proc('test.rb', options) do
loop do
10.times do |i|
puts "#{i}\n"
sleep(1)
end
end
end
I start the daemon with
ruby simple_daemon.rb start
and stop it with
ruby simple_daemon.rb stop
Is it possible to softly stop the daemon, letting it end its last loop before killing its process, so that I'm sure that it prints all the 10 numbers one last time?
You need to trap the TERM signal which is sent when you call stop and handle it yourself. Your code could be something like this :
Daemons.run_proc('test.rb', options) do
stopped = false
Signal.trap("TERM") do
stopped = true
end
while not stopped
10.times do |i|
puts "#{i}\n"
sleep(1)
end
end
end

Ruby Daemons log rotation

When I'm setting logging parameters to the Daemons (1.1.0) gem, how would I achieve similar behavior to this line?
logger = Logger.new('foo.log', 10, 1024000)
Daemon options:
options = {
:ARGV => ['start'],
:dir_mode => :normal,
:dir => log_dir,
:multiple => false,
:ontop => false
:mode => :exec,
:backtrace => true,
:log_output => true
}
Unfortunately the Daemons gem does not use Logger. It redirects STDOUT and STDERR directly to a file.
You can see the details of how the redirection works here:
https://github.com/ghazel/daemons/blob/master/lib/daemons/daemonize.rb#L241-261
Because of this, you will have to use something like logrotate and restart the daemon if you want to do log file rotation.
If this is not acceptable, I would suggest using Logger directly like you provided in the question.

How do I have the :default Rake task depend on a task with arguments?

I have been playing around with Rake and Albacore, to see if I can replace our existing MSBuild script that deploys software with something that isn't XML. I have a task that will change the debug value inside a web.config to false. The task takes the directory of the web.config as an argument, but I can't quite figure out the syntax needed to supply this argument in the default task.
require 'albacore'
require 'nokogiri'
deployment_path = 'c:/test-mars-deploy'
task :default => [ :build, :publish, :update_web_config['c:/test-mars-deploy'] ]
task :update_web_config, :deploy_path do |t, args|
deployment_path = #{args[:deploy_path]}
web_config_path = File.join deployment_path, 'Web.config'
File.open(web_config_path, 'r+') do |f|
doc = Nokogiri::XML(f)
puts 'finding attribute'
attribute = doc.xpath('/configuration/system.web/compilation')
attribute.attr('debug', 'false')
puts attribute.to_xml
end
File.delete(web_config_path)
File.new(web_config_path, 'w') do |f|
f.write(doc.to_s)
end
end
The task dependency notation doesn't support passing arguments. It only takes names or symbols referring to task names.
task :default => [ :build, :publish, :update_web_config['c:/test-mars-deploy'] ]
You'd need to do something like this.
task :default => [ :build, :publish ] do
Rake::Task[:update_web_config].invoke 'c:/test-mars-deploy'
end
Remember, though, invoke will only work once per task, even with different arguments. It's the real dependency chain invoke. But, it will call all dependent tasks. You can use execute if you need multiple executions, but that won't call dependent tasks.
Rake::Task[:update_web_config].invoke 'c:/test-mars-deploy'
Rake::Task[:update_web_config].execute 'c:/test-mars-deploy2'
Rake::Task[:update_web_config].execute 'c:/test-mars-deploy3'
In general, I don't recommend either of these approaches. Calling invoke or execute seems to me to indicate a poorly structured task. You simply don't have this problem if you don't prematurely parameterize.
web_config = 'c:/test-mars-deploy/Web.config'
task :update_web_config do
File.open(web_config, 'r+') do |file|
# ...
end
end
If you must parameterize, provide an array or FileList and generate the tasks per item.
web_configs = FileList['c:/test-*/Web.config']
web_configs.each do |config|
task config do
File.open(config, 'r+') do |file|
# ...
end
end
end
task :update_all_web_configs => web_configs
Better yet, I published a config update task that does all of this mess for you! Provide a FileList to update and a hash of xpath queries => replacements.
appconfig :update_web_configs do |x|
x.files = FileList['c:/test-*/Web.config']
x.replacements = {
"/configuration/system.web/compilation/#debug" => 'False' }
end
I think you might have to use the old style parameter passing, eg:
nicholas#hal:/tmp$ cat Rakefile
task :default => :all
deploy_path = ENV['deploy_path'] || "c:/some_path"
task :all do |t, args|
puts deploy_path.inspect
end
And invoke with:
nicholas#hal:/tmp$ rake
(in /tmp)
"c:/some_path"
Or, to override the path:
nicholas#hal:/tmp$ rake deploy_path=c:/other_path
(in /tmp)
"c:/other_path"
basically, you name your args as extra symbols after the name of the task. an args param will get passed into the block that responds to the name of your args, and you can invoke the task passing the args in square brackets ([])
ree-1.8.7-2010.02#rails3 matt#Zion:~/setup$ cat lib/tasks/blah.rake
task :blah, :n do |t, args|
puts args.n
end
ree-1.8.7-2010.02#rails3 matt#Zion:~/setup$ rake blah[20]
(in /home/matt/setup)
20
The task dependency notation does in fact support passing arguments. For example, say "version" is your argument:
task :default, [:version] => [:build]
task :build, :version do |t,args|
version = args[:version]
puts version ? "version is #{version}" : "no version passed"
end
Then you can call it like so:
$ rake
no version passed
or
$ rake default[3.2.1]
version is 3.2.1
or
$ rake build[3.2.1]
version is 3.2.1
However, I have not found a way to avoid specifying the task name (default or build) while passing in arguments. Would love to hear if anyone knows of a way.

Resources