My favorites | Sign in
Project Logo
                
Search
for
Updated Mar 18, 2009 by matt.zukowski
Labels: Featured, Phase-Implementation, Phase-Deploy
PicnicTutorial  
Step-by-step tutorial describing how to build a Picnic-enabled Camping app

Introduction

Picnic is a set of extensions for Camping. It is assumed that if you're using Picnic, you're building a Camping app. If you're not familliar with Camping, have a look here and here.

Camping, on its own is a great little framework. It's especially useful for building small HTTP-based services, where Rails just doesn't make sense. A good example of just this sort of Camping app is RubyCAS-Server. RubyCAS-Server doesn't need Rails' extensive user interface niceties, since it's main purpose is to act as an HTTP service accessible behind the scenes by other services. Rails also has some serious problems that make it unusable for certain purposes. For example, Rails controllers are not concurrent, meaning that if a Rails controller is busy doing something, it can't respond to other requests. Generally for the kinds of applications Rails is good at this isn't an issue, but it can be a big problem for network services that rely on transactional conversations between each other. Camping does not have this limitation, making it perfect for building network service applications.

Unfortunately, Camping does have its shortcomings. For one, deploying a Camping app in a production context as part of a bigger Linux infrastructure is problematic. Secondly, developing a Camping-based app and then distributing it as a stand-alone application via the normal Ruby mechanisms (i.e. RubyGems) is not easy.

Enter Picnic. From the ground up, Picnic is designed to make it easy to:

  1. Deploy your Camping app as a well-behaved Linux service (complete with init.d startup mechanism, daemonization, pid management, and /etc-based configuration).
  2. Distribute your Camping app as a RubyGem that others can easily install with a single call to gem install your_app.

The hope is that thanks to Picnic, Ruby developers can start easily building simple network applications, proliferating Ruby as the tool of choice for the service-oriented architecture approach. Picnic also works well with Reststop, making it possible to easily build RESTful services in Camping.

If this sounds like something that might be useful to you, read on.

Prerequisites

As mentioned above, it is assumed that you already have some familiarity with Camping. If you're familiar with Camping, then you're also probably reasonably proficient with Ruby and know how to deal with RubyGems.

This tutorial also assumes that you're on a Linux-based system with Ruby and RubyGems already installed. Most of these instructions will almost certainly work just fine on MacOS X and Windows, but you may have to do some translating.

To start, you should install the Picnic and newgem gems:

gem install picnic
gem install newgem

newgem is a collection of scripts for generating a skeleton Ruby application, easily packagable as a RubyGem. If you're familliar with Rails, newgem is similar to the rails script, but instead of generating a starter Rails app, it will generate a starter RubyGem, complete with a Rakefile and some starter code.

Generating the Skeleton

In this tutorial we will take the canonical Camping Blog app, and Picnic-fy it. We want our Blog application to be distributable as a gem, and we want end users to be able to run it with minimal configuration as a stand-alone daemon.

First, lets use the negem script to generate a skeleton directory structure:

newgem blog

Okay, now we've got a blog directory. Inside, it looks something like this:

blog/CHANGELOG.txt
blog/History.txt
blog/README.txt
blog/lib
blog/lib/blog
blog/lib/blog.rb
blog/lib/blog/version.rb
blog/bin
blog/Rakefile
blog/Manifest.txt
blog/test
blog/test/test_helper.rb
blog/test/blog_test.rb
blog/examples
blog/setup.rb

Open up the blog/Rakefile with a text editor, and modify the various values to your likings (i.e. change the DESCRIPTION, EMAIL, etc.)

Towards the very bottom of the Rakefile, you'll see a line like this:

  #p.extra_deps

We need to add Picnic as a dependency, so uncomment this line and change it to:

  p.extra_deps = ['picnic']

Adding Picnic Code

Now we're ready to Picnic-fy our application. Open blog/lib/blog.rb. You'll see some starter code in there. Delete it, and replace it with the following:

$: << File.dirname(File.expand_path(__FILE__))

$APP_NAME ||= 'blog'
$APP_ROOT ||= File.expand_path(File.dirname(__FILE__)+'/..')

require 'rubygems'
require 'picnic'
require 'picnic/logger'

Camping.goes :Blog

Picnic::Logger.init_global_logger!

# Our Camping application's implementation will go here...

The actual implementation of the Camping application will go between the Blog.picnic! and Blog.start_picnic calls.

Adding Camping Code

We're going to use the code from http://code.whytheluckystiff.net/camping/browser/trunk/examples/blog.rb. However, one of the nice features Picnic gives us is the ability to read global settings from a user-defined configuration file (by default, this file is /etc/<app name>/config.yml). So, we're going to slightly modify the Blog code to load certain values from the configuration. For example, we're going to let the user specify the name of their blog using the configuration file. Note the call to Blog::Conf[:blog_title]. Also, we will load the database connection info from the configuration file and establish this connection in our app's create method:

def Blog.create
  Blog::Models::Base.establish_connection Blog::Conf[:database]
  # ...
end

To see what the finished blog/lib/blog.rb file looks like, download, the complete example Picnic application from http://camping-picnic.googlecode.com/files/excample_picnic_app.tar.gz. THIS SAMPLE APP NEEDS TO BE UPDATED FOR PICNIC 0.8!

Note that as with any other Camping application, it is possible to split up your Controllers, Views, and Models modules into separate files. Just put these under lib/blog/controllers.rb, lib/blog/views.rb, and lib/blog/models.rb, and require them in lib/blog.rb somewhere after your Camping.goes :Blog call.

The bin/blog Script

We want to let end-users run their blog as a stand-alone application. Ideally the user should be able to install your gem and then just run blog from the command line. This is exactly what we're going to do.

First, create a bin directory in your blog application. Inside this, create bin/blog and make it executable:

cd blog
mkdir bin
touch bin/blog
chmod +x bin/blog

Now paste in the following code into your bin/blog file:

#!/usr/bin/env ruby

require 'rubygems'
require 'picnic/cli'

cli = Picnic::Cli.new(
  'blog',
  :app_file => File.expand_path(File.dirname(File.expand_path(__FILE__))+"/../lib/blog.rb")
)

cli.handle_cli_input

Before we test our bin script, we need to create the database for our app. If you're using mysql, try something like this:

mysqladmin -u root create blog

You may need to add the -p flag to the above if your root account requires as password.

Now try running bin/blog from your app's root directory. You should find that your application starts up. However, it will complain about a missing example configuration file. We'll address this in the next step.

Creating a Default Configuration File

Every Picnic app is configured via a YAML-based conf file. At the very least, this file will tell Picnic what web server to use (webrick or mongrel) and what port to run on. If your application uses a database, you'll also want to load your connection settings from here. The configuration file is essentially just a big Hash, so feel free to store application-specific settings here as well.

Since we want our applications to run out-of-the-box, with minimal user configuration, every Picnic app should include an example config file. This should always be called config.example.yml and should sit in your application's root directory. The first time the user runs your app, Picnic will automatically copy the example config into /etc/<your app>/config.yml (although the end user can change this location using the --config option).

Lets create an example config file for our blog application. It's a good idea to comment this file liberally so that the end user can figure out how to modify it for their needs. Here is our config.example.yml file:

# This is a configuration file for the Blog daemon.

# AN IMPORTANT NOTE ABOUT YAML CONFIGURATION FILES:
# !!! Be sure to use spaces instead of tabs for indentation, as YAML is very
# !!! sensitive to white-space inconsistencies!

##### HTTP SERVER #####################################################################

# Under what HTTP environment are you running the Fluxr server? The following methods
# are currently supported:
#
# webrick -- simple stand-alone HTTP server; this is the default method
# mongrel -- fast stand-alone HTTP server; much faster than webrick, but 
#            you'll have to first install the mongrel gem
# 

### webrick example

server: webrick
port: 8106

### webrick SSL example

#server: webrick
#port: 443
#ssl_cert: /path/to/your/ssl.pem

# if the private key is separate from cert:
#ssl_key: /path/to/your/private_key.pem


### mongrel example

#server: mongrel
#port: 8106

# It is possible to run mongrel over SSL, but you will need to use a reverse proxy
# (try Pound or Apache).


##### DATABASE ########################################################################

# The Blog needs a database to store its records.
# 
# By default, we use MySQL, since it is widely used and does not require any additional
# ruby libraries besides ActiveRecord.
#
# With MySQL, your config would be something like the following:
# (be sure to create the blog database in MySQL beforehand,
#   i.e. `mysqladmin -u root create blog`)

database:
  adapter: mysql
  database: blog
  username: root
  password: 
  host: localhost


# Instead of MySQL you can use SQLite3, PostgreSQL, MSSQL, or anything else supported 
# by ActiveRecord.
#
# If you do not have a database server available, you can try using the SQLite3
# back-end. SQLite3 does not require it's own server. Instead all data is stored
# in local files. For SQLite3, your configuration would look something like the
# following (don't forget to install the 'sqlite3-ruby' gem first!):
#
#database:
#  adapter: sqlite3
#  dbfile: /var/lib/blog.db


##### BLOG ############################################################################

# This sets the title that should appear at the top of our Blog pages.

blog_title: My Blog

##### LOGGING #########################################################################

# This log is where you'll want to look in case of problems. 
# 
# By default, we will try to create a log file named 'blog.log' in the current 
# directory (the directory where you're running the blog from). A better place to put 
# the log is in /var/log, but you will have to run blog as root or otherwise give 
# it permissions.
# 
# Set the level to DEBUG if you want more detailed logging. Other options are
# INFO, WARN, and ERROR (DEBUG is most verbose, ERROR is least).

log:
  file: blog.log
  level: DEBUG
#  file: /var/log/blog.log
#  level: INFO

Okay, now if you try running bin/blog, you should see something like this:

Adding Picnic functionality to Blog from /usr/lib/ruby/gems/1.8/gems/picnic-0.0.0.14/lib...
Loading configuration for Blog from '/etc/blog/config.yml'...

BLOG SERVER HAS NOT YET BEEN CONFIGURED!!!

Attempting to copy sample configuration from '/home/URBACON/mzukowski/blog/bin/../config.example.yml' to '/etc/blog/config.yml'...

It appears that you do not have permissions to create the '/etc/blog/config.yml' file. Try running this command using sudo (as root).

The application complains about not being able to write the config file. By default, Picnic will try to put the configuration file in /etc/blog/config.yml, but we need root privileges to write to this directory. Either run the script as root (sudo bin/blog) or specify a different location for the configuration file (bin/blog -c ~/blog.yml).

Now you should get a message about the sample configuration being created. Modify the generated config file if necessary, and run again. This time the server should launch, and your Blog application should be accessible at http://localhost:8106 (or whatever port you specified in your configuration file).

init.d and the bin/blog-ctl Script

The bin/blog script we created above is great for launching your application from the command line, but if we want our app to function as part of a Linux server, we'll have to integrate it into Linux's init.d mechanism for managing services.

To this end we'll create a bin/blog-ctl script. This takes care of launching your bin/blog as a background daemon process, and provides a command line interface similar to apachectl.

Create a the file bin/blog-ctl and make sure it's executable (chmod +x bin/blog-ctl). Paste in the following code:

#!/usr/bin/env ruby

require 'rubygems'
require 'picnic/service_control'

ctl = Picnic::ServiceControl.new('blog')

ctl.handle_cli_input

You should now be able to use the blog-ctl script to start and stop the server from the command line using blog-ctl start and bloc-ctl stop. We can then make use of this inside an init.d script.

We can make use of this for init.d like so:

  1. Create the file /etc/init.d/blog
  2. Make it executable: chmod +x /etc/init.d/blog
  3. Write a simple bash script that uses blog-ctl. The details will vary depending on your Linux distribution. For SuSE it might look something like this:
#!/bin/sh
CTL=foo-ctl
. /etc/rc.status

rc_reset
case "$1" in
    start)
        $CTL start
        rc_status -v
        ;;
    stop)
        $CTL stop
        rc_status -v
        ;;
    restart)
        $0 stop
        $0 start
        rc_status
        ;;
    status)
        $CTL status
        rc_status -v
        ;;
    *)
        echo "Usage: $0 {start|stop|status|restart}"
        exit 1
        ;;
esac
rc_exit

You should now be able to launch your application like any other init.d script (just make sure that foo-ctl is installed in your executable PATH -- in the next section we'll discuss how to do this automatically).

Note that there is currently no way to have the init.d automatically installed for the end user. You will have to provide instructions for doing this in your end-user documentation. You can (and should) however include the app-ctl script with your app, since this makes launching your application as a daemon much easier for the end user.

Packaging Your Picnic App as a RubyGem

In order to make our Picnic app easily distributable, we'll want to package it as a RubyGem. Because we used newgem to generate our application's skeleton, the process of packing our application into a gem is easy.

The one thing left to do is make some final changes to our app's Rakefile and then update the Manifest.txt file to include all of the files we want package into the gem.

Open up blog/Rakefile. Towards the bottom, you'll see the following line:

  #p.spec_extras    - A hash of extra values to set in the gemspec.

Uncomment this, and change it to:

  p.spec_extras = {:executables => ['blog', 'blog-ctl']}

This will ensure that our two bin scripts are installed into the end user's /usr/bin directory, so that they are executable just like any other system-installed application.

Now we need to update the Manifest.txt file. This file contains a list of directories and files that should be packed into the gem. Without changes, it will probably look something like this:

Rakefile
README.txt
CHANGELOG.txt
Manifest.txt
setup.rb
lib/blog/version.rb
lib/blog.rb
test/test_helper.rb
test/blog_test.rb

We should add to this our bin scripts and the config.example.yml file. This can be done automatically using the following command:

rake check_manifest | patch Manifest.txt -

Your updated Manifest.txt file should now look like this:

CHANGELOG.txt
History.txt
Manifest.txt
README.txt
Rakefile
bin/blog
bin/blog-ctl
config.example.yml
lib/blog.rb
lib/blog/version.rb
setup.rb
test/blog_test.rb
test/test_helper.rb

Now we're ready to package our app into a gem:

rake package

This will generate pkg/blog-0.0.1.gem. Go ahead and install this gem so that we can test it out:

sudo gem install pkg/blog-0.0.1.gem

You should now find that you can run the blog and blog-ctl commands directly from your bash shell. That's it. Our application is fully packaged and ready for distribution!

Note that the version number attached to your gem is set in your lib/version.rb file. You should increment this anytime you release a new version of the gem.

Publishing Your App to RubyForge

As a final step, you may want to make your app distributable via RubyForge. This will let people install your application just by typing:

gem install blog

RubyForge maintains the default gem repository from which the gem command obtains its list of packages.

To register your app with RubyForge you will have to:

  1. Obtain a RubyForge account
  2. Register your project (you'll have to wait a day or so for your project to be approved)
  3. Upload your .gem file to your project's file distribution page

Once your gem is uploaded, you'll have to wait approximately one hour for RubyForge to update its gem index. At that point your application should become installable as a remote gem.


Comment by shane.swartz, Jul 21, 2009

The service_control.rb file has some TODO's in it that I've completed in order to allow the rubycas-server rubycas-server-ctl script to work. Here is the updated service_control.rb file:

require 'optparse'

module Picnic

  1. Provides functionality for controlling a Picnic-based server as
  2. an init.d service.
  3. Based on code from rubycas-server by jzylks and matt.zukowski.
  4. Usage Example:
  5. #!/usr/bin/env ruby
  6. require 'rubygems'
  7. require 'picnic/service_control'
  8. ctl = Picnic::ServiceControl?.new('foo')
  9. ctl.handle_cli_input
  10. The file containing this code can now be used to control the Picnic
  11. app 'foo'.
  12. For, example, lets say you put this in a file called <tt>foo-ctl</tt>.
  13. You can now use <tt>foo-ctl</tt> on the command line as follows:
  14. chmod +x foo-ctl
  15. ./foo-ctl -h
  16. ./foo-ctl start --verbose --config /etc/foo/config.yml
  17. ./foo-ctl stop --config /etc/foo/config.yml
  18. Your <tt>foo-ctl</tt> script can also be used as part of Linux's init.d
  19. mechanism for launching system services. To do this, create the file
  20. <tt>/etc/init.d/foo</tt> and make sure that it is executable. It will
  21. look something like the following (this may vary depending on your Linux
  22. distribution; this example is for SuSE):
  23. #!/bin/sh
  24. CTL=foo-ctl
  25. . /etc/rc.status
  26. rc_reset
  27. case "$1" in
  28. start)
  29. $CTL start
  30. rc_status -v
  31. ;;
  32. stop)
  33. $CTL stop
  34. rc_status -v
  35. ;;
  36. restart)
  37. $0 stop
  38. $0 start
  39. rc_status
  40. ;;
  41. status)
  42. $CTL status
  43. rc_status -v
  44. ;;
  45. )
  46. echo "Usage: $0 {start|stop|status|restart}
  47. exit 1
  48. ;;
  49. esac
  50. rc_exit
  51. You should now be able to launch your application like any other init.d script
  52. (just make sure that <tt>foo-ctl</tt> is installed in your executable <tt>PATH</tt>
  53. -- if your application is properly installed as a RubyGem?, this will be done automatically).
  54. On most Linux systems, you can make your app start up automatically during boot by calling:
  55. chkconfig -a foo
  56. On Debian and Ubuntu, it's:
  57. update-rc.d foo defaults
class ServiceControl?
attr_accessor :app, :options
  1. Creates a new service controller.
  2. +app+:: The name of the application. This should match the name of the
  3. binary, which by default is expected to be in the same directory
  4. as the service control script.
  5. +options+:: A hash overriding default options. The options are:
  6. +bin_file+:: The name of the binary file that this control
  7. script will use to start and stop your app.
  8. +pid_file+:: Where the app's PID file (containing the app's
  9. process ID) should be placed.
  10. +verbose+:: True if the service control script should report
  11. everything that it's doing to STDOUT.
def initialize(app, options = {})
@app = app

@options = options @options:bin_file? ||= "bin/#{app}" @options:pid_file? ||= "/etc/#{app}/#{app}.pid" @options:conf_file? ||= nil @options:verbose? ||= false

@options = options
end
  1. Parses command line options given to the service control script.
def handle_cli_input
OptionParser?.new do |opts|
opts.banner = "Usage: #{$0} (start|stop|restart) options?" opts.banner += "\n#{app} is only usable when using webrick or mongrel"
opts.on("-c", "--config FILE", "Path to #{app} configuration file") { |value| @options:conf_file? = value } opts.on("-P", "--pid_file FILE", "Path to #{app} pid file") { |value| @options:pid_file? = value } opts.on('-v', '--verbose', "Print debugging information to the console") { |value| @options:verbose? = value }
if ARGV.empty?
puts opts exit
else
@cmd = opts.parse!(ARGV) if @cmd.nil?
puts opts exit
end
end
end
if !@options:conf_file?.nil? && !File.exists?(@options:conf_file?)
puts "Invalid path to #{app} configuration file: #{@options:conf_file?}" exit
end
case @cmd0? when "start":
puts "Starting #{app}..." start
when "stop":
puts "Stopping #{app}..." stop
when "restart":
puts "Restarting #{app}..." stop start
when "status":
puts "Checking status of #{app}..." status
else
puts "Invalid command. Usage: #{app}-ctl -cPv? start|stop|restart|status"
end
exit
end
def start
  1. use local app bin if it exists and is executable -- makes debugging easier
bin = options:bin_file?

if File.exists?(bin)
exec = "ruby #{bin}"
else
exec = app
end

case get_state when :ok
$stderr.puts "#{app} is already running" exit 1
when :not_running_pid, :empty_pid
$stderr.puts "The pid file '#{@options:pid_file?}' exists but #{app} is not running." +
" The pid file will be automatically deleted for you, but this shouldn't have happened!"
File.delete(@options:pid_file?)
when :dead
$stderr.puts "The pid file '#{@options:pid_file?}' exists but #{app} is not running." +
" Please delete the pid file first."
exit 1
when :running_missing_pid
$stderr.puts "#{app} is already running (pid file is missing)." exit 1
when :not_running_no_pid
  1. we should be good to go
else
$stderr.puts "#{app} could not be started. Try looking in the log file for more info." exit 1
end
cmd = "#{exec} -d -P #{@options:pid_file?}" cmd += " -c #{@options:conf_file?}" if !@options:conf_file?.nil?
puts "<<< #{cmd}" if @options:verbose?
output = #{cmd}
puts ">>> #{output}" if @options:verbose?
sleep (1)

s = get_state

puts ">>> STATE: #{s.to_s}" if options:verbose?
if s == :ok
exit 0
else
$stderr.puts "\n#{app} could not start properly!\nTry running with the --verbose option for details." case s when :running_missing_pid
exit 2
when :not_running_no_pid
exit 4
when :not_running_pid
exit 3
when :dead
exit 1
else
exit 4
end
end
end
def stop
killSigs = 'QUIT', 'KILL'? if File.exists? @options:pid_file?
pid = open(@options:pid_file?).read.to_i for signal in killSigs
begin
puts ">>> Attempting to kill with signal #{signal}" if options:verbose? Process.kill(signal, pid) sleep(3) s = get_state
puts ">>> STATE: #{s.to_s}" if options:verbose?
if s == :not_running_pid
begin
puts ">>> Stopped #{app} attempting to delete pid file" if options:verbose? File.delete(@options:pid_file?)
rescue Exception
$stderr.puts "Failed to remove the pid file '#{@options:pid_file?}'." exit 1
end exit 0
elsif s == :not_running_no_pid
exit 0
end
rescue Errno::ESRCH
$stderr.puts "#{app} process '#{pid}' does not exist." exit 1
end
end s = get_state puts ">>> STATE: #{s.to_s}" if options:verbose? if s == :not_running_pid
begin
puts ">>> Stopped #{app} attempting to delete pid file" if options:verbose? File.delete(@options:pid_file?)
rescue Exception
$stderr.puts "Failed to remove the pid file '#{@options:pid_file?}'." exit 1
end exit 0
elsif s == :not_running_no_pid
exit 0
else
$stderr.puts "\n#{app} could not stop properly!\nTry running with the --verbose option for details." case s when :ok
exit 3
when :dead
exit 1
when :running_missing_pid
exit 2
else
exit 4
end
end
else
pid=pgrep #{app} pid.chomp! puts ">>> Stopping with no pid file - pid: <#{pid}>" if options:verbose? if !pid.empty?
for signal in killSigs
begin
puts ">>> Attempting to kill with signal #{signal}" if options:verbose? Process.kill(signal, pid.to_i) sleep(3) s = get_state
puts ">>> STATE: #{s.to_s}" if options:verbose?
if s == :not_running_pid
begin
puts ">>> Stopped #{app} attempting to delete pid file" if options:verbose? File.delete(@options:pid_file?)
rescue Exception
$stderr.puts "Failed to remove the pid file '#{@options:pid_file?}'." exit 1
end exit 0
elsif s == :not_running_no_pid
exit 0
end
rescue Errno::ESRCH
$stderr.puts "#{app} process '#{pid}' does not exist." exit 1
end
end s = get_state puts ">>> STATE: #{s.to_s}" if options:verbose? if s == :not_running_pid
begin
puts ">>> Stopped #{app} attempting to delete pid file" if options:verbose? File.delete(@options:pid_file?)
rescue Exception
$stderr.puts "Failed to remove the pid file '#{@options:pid_file?}'." exit 1
end exit 0
elsif s == :not_running_no_pid
exit 0
else
$stderr.puts "\n#{app} could not stop properly!\nTry running with the --verbose option for details." case s when :ok
exit 3
when :dead
exit 1
when :running_missing_pid
exit 2
else
exit 4
end
end
else
$stderr.puts "#{app} is already stopped." exit 4
end
end
end
def status
s = get_state puts ">>> STATE: #{s.to_s}" if options:verbose? case s when :ok
puts "#{app} appears to be up and running." exit 0
when :not_running_pid
$stderr.puts "#{app} does not appear to be running (pid file exists)." exit 3
when :empty_pid
$stderr.puts "#{app} does not appear to be running (pid file exists but is empty)."
when :not_running_no_pid
$stderr.puts "#{app} is not running." exit 1
when :running_missing_pid
$stderr.puts "#{app} is running (pid file is missing)." exit 1
when :dead
$stderr.puts "#{app} is dead or unresponsive." exit 102
end
end
def get_state
  1. FIXME: This is a poor attempt at trying to fix a problem where occassionally
  2. an empty pid_file is read, probably because it has not yet been
  3. fully written.
sleep 0.5
if File.exists? @options:pid_file?
pid = File.read(@options:pid_file?).strip puts ">>> Getting state with pid file: #{pid}" if options:verbose?
return :empty_pid unless pid and !pid.empty? # pid file exists but is empty
# # Changed 'state=' to 's=' so that this works on Solaris # # The following line modified by Shane Swartz # state = ps -p #{pid} -o state=.strip
state = ps -p #{pid} -o s=.strip puts ">>> pid file: #{pid} - state: #{state}" if options:verbose? if state == ''
return :not_running_pid
elsif state == 'O' || state == 'S'
state == 'R'
return :ok
else
return :dead
end
else
  1. TODO: scan through the process table to see if server is running without pid file
  2. The following code added by Shane Swartz
pid=pgrep #{app} pid.chomp! puts ">>> Getting state with no pid file - pid: <#{pid}>" if options:verbose? if !pid.empty?
state = ps -p #{pid} -o s=.strip puts ">>> No pid file - state: #{state}" if options:verbose? if state == ''
return :not_running_no_pid
elsif state == 'O' || state == 'S'
state == 'R'
return :running_missing_pid
else
return :dead
end
else
return :not_running_no_pid
end
end
end
end
end


Sign in to add a comment
Hosted by Google Code