Parker Smith Software

 
 

background process manager script

By Brian Webb

28 May 2009

We're working on a project right now that uses starling + workling for sending email in the background as well as daemons to send out send out periodic emails (also in the background). So in our development environment it quickly became a pain to start starling, then start the daemon every time someone started working on the project, then killing processes when you're done. We kept hitting errors in the code, only to realize that it was because the background task mangers weren't running. So we came up with this little script to make it easy, just:

1
2

script/background start development

and then when you're all done.

1
2

script/background stop

Here's the code, just put it in script/background of your rails project:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

#!/usr/bin/env ruby 

# == Synopsis 
#   This script manages the creation and destruction of starling and workling processes
#   as well as any background daemons
#
# == Examples
#   script/background start development
#   script/background stop
#
# == Usage 
#   background [start|stop] rails_environment
#
#   For help use: background -h
#
# == Options
#   -h, --help          Displays help message
#   -v, --version       Display the version, then exit
#   -q, --quiet         Output as little as possible, overrides verbose
#   -V, --verbose       Verbose output
#
#
# == Author
#   Brian Webb <brian@parkersmithsoftware.com>
#
# == Copyright
#   Copyright (c) 2009 Parker Smith. Licensed under the MIT License:
#   http://www.opensource.org/licenses/mit-license.php


require 'optparse' 
require 'rdoc/usage'
require 'ostruct'
require 'date'


class App
  VERSION = '0.0.1'
  
  attr_reader :options

  def initialize(arguments, stdin)
    @arguments = arguments
    @stdin = stdin
    
    # Set defaults
    @options = OpenStruct.new
    @options.verbose = false
    @options.quiet = false
    @local_exists = false
    @remote_exists = false

  end #end initialize


  # Parse options, check arguments, then process the command
  def run
        
    if parsed_options? && arguments_valid? 
      
      puts "Start at #{DateTime.now}\n\n" if @options.verbose
      
      output_options if @options.verbose # [Optional]
            
      process_arguments            
      process_command
      
      puts "\nFinished at #{DateTime.now}" if @options.verbose
      
    else
      output_usage
    end
      
  end
  
  protected
  
    def parsed_options?
      
      # Specify options
      opts = OptionParser.new 
      opts.on('-v', '--version')    { output_version ; exit 0 }
      opts.on('-h', '--help')       { output_help }
      opts.on('-V', '--verbose')    { @options.verbose = true }  
      opts.on('-q', '--quiet')      { @options.quiet = true }
            
      opts.parse!(@arguments) rescue return false
      
      process_options
      true      
    end

    # Performs post-parse processing on options
    def process_options
      @options.verbose = false if @options.quiet
    end
    
    def output_options
      puts "Options:\n"
      
      @options.marshal_dump.each do |name, val|        
        puts "  #{name} = #{val}"
      end
    end

    # True if required arguments were provided
    def arguments_valid?
    
      if @arguments.length >= 1
        if @arguments[0] == "stop"
          true
        else
          if @arguments[1] == "development" || @arguments[1] == "test" || @arguments[1] == "production"
            true
          end
        end
      end
    
    end
    
    # Setup the arguments
    def process_arguments
      @start = @arguments[0] == "start" ? true : false
      @stop = @arguments[0] == "stop" ? true : false
      @env = @arguments.length > 1 ? @arguments[1] : nil
    end
    
    def output_help
      output_version
      RDoc::usage() #exits app
    end
    
    def output_usage
      RDoc::usage('usage') # gets usage from comments above
    end
    
    def output_version
      puts "#{File.basename(__FILE__)} version #{VERSION}"
    end
    
    def process_command

      if @start
        
        starling_command = <<-end_command
          cd #{File.dirname(__FILE__) + '/../'} && starling -d -P tmp/pids/starling.pid -q log/
        end_command

        workling_command = <<-end_command
          cd #{File.dirname(__FILE__) + '/../'} && script/workling_client start
        end_command
        
        daemon_command = <<-end_command
          cd #{File.dirname(__FILE__) + '/../'} && RAILS_ENV=#{@env} lib/daemons/mailer_ctl start
        end_command

        starling_command.gsub!(/\s+/, " ")
        workling_command.gsub!(/\s+/, " ")
        daemon_command.gsub!(/\s+/, " ")

        puts "\nStarting Starling..." unless @options.quiet
        s_success = Kernel.system(starling_command)
        if !s_success && $?.exitstatus != 0
          raise "!!! Starling startup failed !!!"
        else
          puts "Starling started successfully.\n\n" unless @options.quiet
        end
        
        sleep 1
        
        puts "Starting Workling..." unless @options.quiet
        w_success = Kernel.system(workling_command)
        if !w_success && $?.exitstatus != 0
          raise "!!! Workling startup failed !!!"
        else
          puts "Workling started successfully.\n\n" unless @options.quiet
        end
        
        sleep 1
        
        puts "Starting mailer daemon..." unless @options.quiet
        d_success = Kernel.system(daemon_command)
        if !d_success && $?.exitstatus != 0
          raise "!!! Mailer daemon startup failed !!!"
        else
          puts "Mailer daemon started successfully.\n\n" unless @options.quiet
        end
        
      elsif @stop
        
        starling_command = <<-end_command
          kill `ps -aef | grep starling | grep -v grep | awk '{print $2}'`
        end_command

        workling_command = <<-end_command
          cd #{File.dirname(__FILE__) + '/../'} && script/workling_client stop
        end_command
        
        daemon_command = <<-end_command
          cd #{File.dirname(__FILE__) + '/../'} && lib/daemons/mailer_ctl stop
        end_command

        starling_command.gsub!(/\s+/, " ")
        workling_command.gsub!(/\s+/, " ")
        daemon_command.gsub!(/\s+/, " ")
        
        puts "\nStopping Workling..." unless @options.quiet
        w_success = Kernel.system(workling_command)
        if !w_success && $?.exitstatus != 0
          raise "!!! Workling shutdown failed !!!"
        else
          puts "Workling stopped successfully.\n\n" unless @options.quiet
        end
        
        sleep 1

        puts "Stopping Starling..." unless @options.quiet
        s_success = Kernel.system(starling_command)
        if !s_success && $?.exitstatus != 0
          raise "!!! Starling shutdown failed !!!"
        else
          puts "Starling stopped successfully.\n\n" unless @options.quiet
        end
        
        sleep 1
        
        puts "Stopping mailer daemon..." unless @options.quiet
        d_success = Kernel.system(daemon_command)
        if !d_success && $?.exitstatus != 0
          raise "!!! Mailer daemon shutdown failed !!!"
        else
          puts "Mailer daemon stopped successfully.\n\n" unless @options.quiet
        end
  
      end

    end #end process_command

end #end App Class


# Create and run the application
app = App.new(ARGV, STDIN)
app.run

No Spam: 7 + 4 =