homeq 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +103 -0
- data/COPYING +348 -0
- data/README.rdoc +64 -0
- data/Rakefile +131 -0
- data/bin/hq +6 -0
- data/config/boot.rb +224 -0
- data/config/databases/frontbase.yml +28 -0
- data/config/databases/mysql.yml +54 -0
- data/config/databases/oracle.yml +39 -0
- data/config/databases/postgresql.yml +48 -0
- data/config/databases/sqlite2.yml +16 -0
- data/config/databases/sqlite3.yml +19 -0
- data/config/environment.rb +20 -0
- data/config/environments/development.cfg +35 -0
- data/config/environments/production.cfg +35 -0
- data/config/environments/test.cfg +35 -0
- data/config/generators/job/templates/job.rb.erb +20 -0
- data/config/generators/message/templates/messages/MESSAGE.proto.erb +12 -0
- data/config/generators/model/templates/models/MODEL.rb.erb +3 -0
- data/config/generators/service/templates/services/SERVICE.rb.erb +43 -0
- data/config/homeq.cfg +35 -0
- data/extras/consumer.rb +85 -0
- data/extras/homeq.cfg +49 -0
- data/extras/hqd.rb +33 -0
- data/extras/producer.rb +79 -0
- data/extras/simple_consumer.rb +53 -0
- data/lib/homeq/base/base.rb +44 -0
- data/lib/homeq/base/commando.rb +81 -0
- data/lib/homeq/base/config.rb +99 -0
- data/lib/homeq/base/exception.rb +48 -0
- data/lib/homeq/base/histogram.rb +141 -0
- data/lib/homeq/base/logger.rb +185 -0
- data/lib/homeq/base/ohash.rb +297 -0
- data/lib/homeq/base/options.rb +171 -0
- data/lib/homeq/base/poolable.rb +100 -0
- data/lib/homeq/base/system.rb +446 -0
- data/lib/homeq/cli.rb +35 -0
- data/lib/homeq/cp/commands.rb +71 -0
- data/lib/homeq/cp/connection.rb +97 -0
- data/lib/homeq/cp/cp.rb +30 -0
- data/lib/homeq/cp/server.rb +105 -0
- data/lib/homeq/sobs/client.rb +119 -0
- data/lib/homeq/sobs/connection.rb +635 -0
- data/lib/homeq/sobs/foreman.rb +237 -0
- data/lib/homeq/sobs/job.rb +66 -0
- data/lib/homeq/sobs/message.rb +49 -0
- data/lib/homeq/sobs/queue.rb +224 -0
- data/lib/homeq/sobs/sender.rb +150 -0
- data/lib/homeq/sobs/server.rb +654 -0
- data/lib/homeq/sobs/sobs.rb +45 -0
- data/lib/homeq/sobs/topology.rb +111 -0
- data/lib/homeq.rb +106 -0
- data/lib/tasks/Rakefile +49 -0
- data/lib/tasks/database.rake +387 -0
- data/lib/tasks/gem.rake +9 -0
- data/lib/tasks/generate.rake +192 -0
- data/lib/tasks/hq.rake +171 -0
- data/lib/tasks/testing.rake +95 -0
- data/lib/tasks/utility.rb +17 -0
- data/script/console.rb +45 -0
- data/script/generate +7 -0
- data/test/unittest.rb +51 -0
- metadata +222 -0
@@ -0,0 +1,171 @@
|
|
1
|
+
#############################################################################
|
2
|
+
#
|
3
|
+
# $Id: options.rb 42 2008-10-24 05:53:35Z colin $
|
4
|
+
#
|
5
|
+
# Author:: Colin Steele (colin@colinsteele.org)
|
6
|
+
# Homepage::
|
7
|
+
#
|
8
|
+
# TODO: info
|
9
|
+
#
|
10
|
+
#----------------------------------------------------------------------------
|
11
|
+
#
|
12
|
+
# Copyright (C) 2008 by Colin Steele. All Rights Reserved.
|
13
|
+
# colin@colinsteele.org
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 2 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#---------------------------------------------------------------------------
|
23
|
+
#
|
24
|
+
#
|
25
|
+
#############################################################################
|
26
|
+
|
27
|
+
require 'optparse'
|
28
|
+
require 'optparse/time'
|
29
|
+
require 'ostruct'
|
30
|
+
require 'singleton'
|
31
|
+
require 'pp'
|
32
|
+
|
33
|
+
module HomeQ
|
34
|
+
|
35
|
+
module Base
|
36
|
+
|
37
|
+
module Options
|
38
|
+
|
39
|
+
def options
|
40
|
+
@options ||= Options.instance.parse
|
41
|
+
end
|
42
|
+
|
43
|
+
class Options
|
44
|
+
include Singleton
|
45
|
+
|
46
|
+
attr :options, true
|
47
|
+
attr :parser, true
|
48
|
+
|
49
|
+
def initialize
|
50
|
+
@options = OpenStruct.new
|
51
|
+
@options.log_level = false
|
52
|
+
@options.config_file = File.join(HOMEQ_APP_ROOT,
|
53
|
+
'/config/homeq.cfg')
|
54
|
+
@options.queue_name = nil
|
55
|
+
@options.cp_port = nil
|
56
|
+
@options.foreground = false
|
57
|
+
@options.pid_file = false
|
58
|
+
@options.log_file = false
|
59
|
+
@options.dump_topology = false
|
60
|
+
@options.enable_debugging = false
|
61
|
+
|
62
|
+
@parser = OptionParser.new do |opts|
|
63
|
+
opts.banner = "Usage: #{File.basename($0)} [options]"
|
64
|
+
|
65
|
+
opts.separator ""
|
66
|
+
opts.separator "HOMEQ options:"
|
67
|
+
|
68
|
+
# Mandatory argument.
|
69
|
+
opts.on("-c", "--config-file FILE",
|
70
|
+
"Configuration file; defaults to \n\
|
71
|
+
#{@options.config_file}") { |c|
|
72
|
+
@options.config_file = c
|
73
|
+
}
|
74
|
+
opts.on("-q", "--queuename NAME",
|
75
|
+
"This process's queue name") { |q|
|
76
|
+
@options.queue_name = q
|
77
|
+
}
|
78
|
+
opts.on("-p", "--port PORT",
|
79
|
+
Integer,
|
80
|
+
"Control port to listen on.") { |p|
|
81
|
+
@options.cp_port = p
|
82
|
+
}
|
83
|
+
opts.on("-l", "--[no-]log-file LOGFILE",
|
84
|
+
"Log to this file; defaults to \n\
|
85
|
+
#{@options.log_file}") { |o|
|
86
|
+
@options.log_file = o
|
87
|
+
}
|
88
|
+
opts.on("-P", "--pid-file FILE",
|
89
|
+
"Write pid to this file;\n \
|
90
|
+
defaults to " +
|
91
|
+
"/var/run/hq_<queuename>.pid") { |p|
|
92
|
+
@options.pid_file = p
|
93
|
+
}
|
94
|
+
|
95
|
+
# Boolean switches
|
96
|
+
|
97
|
+
opts.on("-v",
|
98
|
+
"--[no-]verbose",
|
99
|
+
"Run verbosely. Additively -vvv") do |v|
|
100
|
+
@options.log_level = 0 unless @options.log_level
|
101
|
+
@options.log_level += 1
|
102
|
+
end
|
103
|
+
opts.on("-f", "--[no-]foreground", "Run in the foreground") do |o|
|
104
|
+
@options.foreground = o
|
105
|
+
end
|
106
|
+
opts.on("-T", "--print-topology",
|
107
|
+
"Using command line options and config file,\n \
|
108
|
+
dump a topology in YAML format.") do |o|
|
109
|
+
@options.dump_topology = o
|
110
|
+
end
|
111
|
+
opts.on("-E", "--print-homeq-env",
|
112
|
+
"Using command line options and config file,\n \
|
113
|
+
display currently set HOMEQ_ENV.") do |o|
|
114
|
+
@options.dump_env = o
|
115
|
+
end
|
116
|
+
opts.on("-D", "--enable-debugging",
|
117
|
+
"Enable rdebug debugging") do |o|
|
118
|
+
@options.enable_debugging = o
|
119
|
+
end
|
120
|
+
|
121
|
+
opts.separator ""
|
122
|
+
opts.separator "Common options:"
|
123
|
+
|
124
|
+
opts.on("-h", "--help", "Show this message") do
|
125
|
+
puts opts
|
126
|
+
exit
|
127
|
+
end
|
128
|
+
|
129
|
+
# Another typical switch to print the version.
|
130
|
+
opts.on("--version", "Show version") do
|
131
|
+
puts OptionParser::Version.join('.')
|
132
|
+
Kernel::exit
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
#
|
138
|
+
# Return a structure describing the options.
|
139
|
+
#
|
140
|
+
def parse
|
141
|
+
# The options specified on the command line will be
|
142
|
+
# collected in *options*. We set default values here.
|
143
|
+
|
144
|
+
begin
|
145
|
+
@parser.parse!(ARGV)
|
146
|
+
rescue OptionParser::ParseError => pe
|
147
|
+
puts @parser
|
148
|
+
raise
|
149
|
+
end
|
150
|
+
|
151
|
+
# Add our cute little override method
|
152
|
+
class << @options
|
153
|
+
def set_configuration(config)
|
154
|
+
@table.each { |k,v|
|
155
|
+
if config.respond_to?(k) && v
|
156
|
+
config.send(k, v)
|
157
|
+
end
|
158
|
+
}
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
@options
|
163
|
+
end # parse()
|
164
|
+
|
165
|
+
end # class Options
|
166
|
+
|
167
|
+
end # module Options
|
168
|
+
|
169
|
+
end # module Base
|
170
|
+
|
171
|
+
end # module HomeQ
|
@@ -0,0 +1,100 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
#############################################################################
|
4
|
+
#
|
5
|
+
# $Id: homeq.rb 8 2008-08-27 20:15:22Z colin $
|
6
|
+
#
|
7
|
+
# Author:: Colin Steele (colin@colinsteele.org)
|
8
|
+
# Homepage::
|
9
|
+
#
|
10
|
+
# TODO: info
|
11
|
+
#
|
12
|
+
#----------------------------------------------------------------------------
|
13
|
+
#
|
14
|
+
# Copyright (C) 2008 by Colin Steele. All Rights Reserved.
|
15
|
+
# colin@colinsteele.org
|
16
|
+
#
|
17
|
+
# This program is free software; you can redistribute it and/or modify
|
18
|
+
# it under the terms of either: 1) the GNU General Public License
|
19
|
+
# as published by the Free Software Foundation; either version 2 of the
|
20
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
21
|
+
#
|
22
|
+
# See the file COPYING for complete licensing information.
|
23
|
+
#
|
24
|
+
#---------------------------------------------------------------------------
|
25
|
+
#
|
26
|
+
#
|
27
|
+
#############################################################################
|
28
|
+
|
29
|
+
module HomeQ
|
30
|
+
|
31
|
+
module Poolable
|
32
|
+
def self.included(base)
|
33
|
+
base.extend(ClassMethods)
|
34
|
+
end
|
35
|
+
def recycle
|
36
|
+
deinitialize
|
37
|
+
if self.class.pool.size < self.class.pool_size
|
38
|
+
self.class.pool.push(self)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
def deinitialize
|
42
|
+
raise "Must be overridden"
|
43
|
+
end
|
44
|
+
module ClassMethods
|
45
|
+
attr :pool, false
|
46
|
+
attr :pool_size, false
|
47
|
+
def pool_init(size)
|
48
|
+
@pool_size = size
|
49
|
+
@pool = []
|
50
|
+
end
|
51
|
+
def new(*args)
|
52
|
+
if @pool.any?
|
53
|
+
o = @pool.shift
|
54
|
+
o.send(:reinitialize, *args)
|
55
|
+
return o
|
56
|
+
end
|
57
|
+
super(*args)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end # module Poolable
|
62
|
+
|
63
|
+
end # module HomeQ
|
64
|
+
|
65
|
+
if $0 == __FILE__
|
66
|
+
|
67
|
+
require 'test/unit/testsuite'
|
68
|
+
require 'test/unit'
|
69
|
+
|
70
|
+
class Foo
|
71
|
+
include HomeQ::Poolable
|
72
|
+
pool_init(1)
|
73
|
+
attr :x, true
|
74
|
+
def initialize(x)
|
75
|
+
@x = x
|
76
|
+
end
|
77
|
+
alias_method :reinitialize, :initialize
|
78
|
+
def deinitialize
|
79
|
+
instance_variables.each {|v|
|
80
|
+
eval "#{v} = nil"
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class TC_MyTest < Test::Unit::TestCase
|
86
|
+
def test_simple
|
87
|
+
f1 = Foo.new(23)
|
88
|
+
assert_equal(23, f1.x)
|
89
|
+
assert_equal(0, Foo.pool.size)
|
90
|
+
f1.recycle
|
91
|
+
assert_equal(1, Foo.pool.size)
|
92
|
+
assert_equal(nil, f1.x)
|
93
|
+
f2 = Foo.new(19)
|
94
|
+
assert_equal(19, f2.x)
|
95
|
+
assert_equal(f1.object_id, f2.object_id)
|
96
|
+
assert_equal(0, Foo.pool.size)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
@@ -0,0 +1,446 @@
|
|
1
|
+
#############################################################################
|
2
|
+
#
|
3
|
+
# $Id: system.rb 48 2008-11-19 05:11:59Z colin $
|
4
|
+
#
|
5
|
+
# Author:: Colin Steele (colin@colinsteele.org)
|
6
|
+
# Homepage::
|
7
|
+
#
|
8
|
+
# TODO: info
|
9
|
+
#
|
10
|
+
#----------------------------------------------------------------------------
|
11
|
+
#
|
12
|
+
# Copyright (C) 2008 by Colin Steele. All Rights Reserved.
|
13
|
+
# colin@colinsteele.org
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 2 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#---------------------------------------------------------------------------
|
23
|
+
#
|
24
|
+
#
|
25
|
+
#############################################################################
|
26
|
+
|
27
|
+
require 'singleton'
|
28
|
+
require 'observer'
|
29
|
+
require 'ruby-prof'
|
30
|
+
|
31
|
+
module HomeQ
|
32
|
+
|
33
|
+
module Base
|
34
|
+
|
35
|
+
class System
|
36
|
+
|
37
|
+
# Run periodic tasks every so many seconds
|
38
|
+
PERIOD_TASK_INTERVAL = 60
|
39
|
+
|
40
|
+
module HomeQ::Base::Commando::InstanceMethods
|
41
|
+
def start_profiling
|
42
|
+
sys.start_profiling
|
43
|
+
end
|
44
|
+
def stop_profiling
|
45
|
+
sys.stop_profiling
|
46
|
+
end
|
47
|
+
document_command "start_profiling", "Begin profiling"
|
48
|
+
document_command "stop_profiling", "End profiling. Results to STDOUT."
|
49
|
+
def enable_debugging(*args)
|
50
|
+
sys.enable_debugging
|
51
|
+
end
|
52
|
+
def disable_debugging
|
53
|
+
sys.disable_debugging
|
54
|
+
end
|
55
|
+
def debug_now
|
56
|
+
sys.debug_now
|
57
|
+
end
|
58
|
+
def add_breakpoint(file, line, expr)
|
59
|
+
sys.add_breakpoint(file, line, expr)
|
60
|
+
end
|
61
|
+
def pid_file(filename=nil)
|
62
|
+
return sys.pid_file unless filename
|
63
|
+
sys.pid_file = filename
|
64
|
+
end
|
65
|
+
def config_file(filename=nil)
|
66
|
+
return sys.config_file unless filename
|
67
|
+
sys.config_file = filename
|
68
|
+
end
|
69
|
+
document_command "enable_debugging", "Begin debugging"
|
70
|
+
document_command("disable_debugging",
|
71
|
+
"End debugging. Results to STDOUT.")
|
72
|
+
document_command "debug_now", "Drop into debugger."
|
73
|
+
document_command "add_breakpoint(file,line,expr)", "Set a breakpoint."
|
74
|
+
config_accessor :foreground
|
75
|
+
config_accessor :dump_topology, 'Cough up topology in YAML format.'
|
76
|
+
config_accessor :dump_env, 'Cough up HOMEQ_ENV.'
|
77
|
+
config_accessor(:period_task_interval,
|
78
|
+
"Run periodic tasks every so many seconds")
|
79
|
+
|
80
|
+
def show_queue(queuename)
|
81
|
+
unless queuename.is_a?(String)
|
82
|
+
return "Supply a queue name in string format, plz."
|
83
|
+
end
|
84
|
+
found = sys.servers.find { |s|
|
85
|
+
s.queue_name == queuename
|
86
|
+
}
|
87
|
+
found ||= sys.queues.find { |s|
|
88
|
+
s.queue_name == queuename
|
89
|
+
}
|
90
|
+
found || "Can't find that queue"
|
91
|
+
end
|
92
|
+
def show_queue_list
|
93
|
+
sys.servers.to_s + "\n" + sys.queues.to_s
|
94
|
+
end
|
95
|
+
document_command "show_queue(qname)", "Display info about a queue"
|
96
|
+
document_command :show_queue_list, "List queues"
|
97
|
+
end
|
98
|
+
|
99
|
+
include Singleton
|
100
|
+
include Observable
|
101
|
+
include Base::Configuration
|
102
|
+
include Base::Logging
|
103
|
+
include Base::Options
|
104
|
+
|
105
|
+
attr :servers, true
|
106
|
+
attr :queues, true
|
107
|
+
attr :config_file, true
|
108
|
+
attr :cp_server, true
|
109
|
+
attr :handlers, true
|
110
|
+
attr :topology, true
|
111
|
+
attr :pid_file, true
|
112
|
+
|
113
|
+
def initialize
|
114
|
+
@handlers = {}
|
115
|
+
@servers = []
|
116
|
+
@queues = []
|
117
|
+
@topology = HomeQ::SOBS::Topology::Topology.new
|
118
|
+
@state = Statemachine.build do
|
119
|
+
state :start do
|
120
|
+
event :init, :waiting_to_run, :delayed_init
|
121
|
+
event :error, :stopped
|
122
|
+
end
|
123
|
+
state :waiting_to_run do
|
124
|
+
on_entry :broadcast_change
|
125
|
+
event :init, :waiting_to_run
|
126
|
+
event :started, :running
|
127
|
+
event :stop, :stopped
|
128
|
+
end
|
129
|
+
state :running do
|
130
|
+
on_entry :broadcast_change
|
131
|
+
event :error, :stopped
|
132
|
+
event :stop, :stopped
|
133
|
+
end
|
134
|
+
state :stopped do
|
135
|
+
on_entry :shutdown
|
136
|
+
event :start, :running
|
137
|
+
event :stop, :stopped
|
138
|
+
event :started, :stopped
|
139
|
+
event :init, :running
|
140
|
+
end
|
141
|
+
state :exit do
|
142
|
+
end
|
143
|
+
end
|
144
|
+
@state.context = self
|
145
|
+
|
146
|
+
catch_signals
|
147
|
+
|
148
|
+
setup_em
|
149
|
+
end
|
150
|
+
|
151
|
+
# Set the system in motion. Initializes, reading command line
|
152
|
+
# args and config file, calls EventMachine::run. If called with
|
153
|
+
# a block, it will yield to the block inside the block passed to
|
154
|
+
# EventMachine::run, so application code will have a chance to
|
155
|
+
# do any startup tasks inside the EventMachine::run block.
|
156
|
+
#
|
157
|
+
# After yielding to your application code (while still in the
|
158
|
+
# EventMachine::run block), it starts the server, queues, and
|
159
|
+
# the control port, and then away we go.
|
160
|
+
def start
|
161
|
+
@state.init
|
162
|
+
if @state.state == :waiting_to_run
|
163
|
+
EventMachine::set_descriptor_table_size(10000)
|
164
|
+
# TODO Hmm. Use this?
|
165
|
+
# EventMachine::set_effective_user("nobody")
|
166
|
+
logger.info {
|
167
|
+
"Starting Eventmachine. Pid: #{Process.pid} " +
|
168
|
+
"HOMEQ_ENV: #{HOMEQ_ENV} HOMEQ_APP_ROOT: #{HOMEQ_APP_ROOT}"
|
169
|
+
}
|
170
|
+
EventMachine::run {
|
171
|
+
yield if block_given?
|
172
|
+
HomeQ::SOBS::Server.create_home_queue(config.queue_name,
|
173
|
+
@handlers[config.queue_name])
|
174
|
+
HomeQ::SOBS::Queue.create_queues_from_topology(config.queue_name)
|
175
|
+
@cp_server = CP::Server.new(config.cp_host, config.cp_port)
|
176
|
+
|
177
|
+
@cp_server.start
|
178
|
+
start_servers
|
179
|
+
start_queues
|
180
|
+
start_periodic_tasks
|
181
|
+
|
182
|
+
@state.started
|
183
|
+
}
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Start a graceful shutdown.
|
188
|
+
def stop
|
189
|
+
@state.stop
|
190
|
+
end
|
191
|
+
|
192
|
+
# We don't do any nice cleanup, just go down fast.
|
193
|
+
def die(msg=nil, exit_status=-1)
|
194
|
+
logger.fatal(msg) if msg
|
195
|
+
exit!(exit_status)
|
196
|
+
end
|
197
|
+
|
198
|
+
# If debugging is already enabled (via enable_debugging), then
|
199
|
+
# call 'debugger'.
|
200
|
+
def debug_now
|
201
|
+
if @debugging
|
202
|
+
debugger
|
203
|
+
else
|
204
|
+
logger.info {
|
205
|
+
"Debugging not started."
|
206
|
+
}
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# If not already enabled, setup for debugging by doing a
|
211
|
+
# require 'ruby-debug', and then a Debugger.start_remote()
|
212
|
+
def enable_debugging
|
213
|
+
if !@debugging
|
214
|
+
logger.info {
|
215
|
+
"Enabled debugging."
|
216
|
+
}
|
217
|
+
@debugging = true
|
218
|
+
require 'ruby-debug'
|
219
|
+
Debugger.start_remote
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# If already debugging, disable it and call Debugger.stop().
|
224
|
+
def disable_debugging
|
225
|
+
if @debugging
|
226
|
+
logger.info {
|
227
|
+
"Disabled debugging"
|
228
|
+
}
|
229
|
+
@debugging = false
|
230
|
+
Debugger.stop
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# Tell the debugger to break at the supplied file and line.
|
235
|
+
def add_breakpoint(file, line, expr)
|
236
|
+
Debugger.add_breakpoint(file, line, expr)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Begin profiling
|
240
|
+
def start_profiling
|
241
|
+
if !@profiling
|
242
|
+
logger.info {
|
243
|
+
'Beginning profiling'
|
244
|
+
}
|
245
|
+
@profiling = true
|
246
|
+
RubyProf.start
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# End profiling. Results are printed to STDOUT.
|
251
|
+
def stop_profiling
|
252
|
+
if @profiling
|
253
|
+
logger.info {
|
254
|
+
'Ending profiling'
|
255
|
+
}
|
256
|
+
@profiling = false
|
257
|
+
result = RubyProf.stop
|
258
|
+
printer = RubyProf::GraphPrinter.new(result)
|
259
|
+
printer.print(STDOUT, 0)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
protected
|
264
|
+
|
265
|
+
# Make sure EventMachine is configured to our liking.
|
266
|
+
def setup_em
|
267
|
+
EventMachine::set_max_timers(1000000)
|
268
|
+
end
|
269
|
+
|
270
|
+
# Tell folks something.
|
271
|
+
def broadcast_change
|
272
|
+
changed
|
273
|
+
notify_observers(self, @state.state)
|
274
|
+
end
|
275
|
+
|
276
|
+
# Lazy initialization; called from start()
|
277
|
+
def delayed_init
|
278
|
+
begin
|
279
|
+
# The queue name and config file name are settings we need
|
280
|
+
# "early", during initialization. If they're set on the
|
281
|
+
# command line, grab them now.
|
282
|
+
options.config_file && (@config_file = options.config_file)
|
283
|
+
options.queue_name && (config.queue_name = options.queue_name)
|
284
|
+
|
285
|
+
raise "No config file set?!" unless config_file
|
286
|
+
config.read_config_file(config_file)
|
287
|
+
options.set_configuration(config)
|
288
|
+
|
289
|
+
if options.dump_topology
|
290
|
+
puts topology.to_yaml
|
291
|
+
exit
|
292
|
+
elsif options.dump_env
|
293
|
+
puts HOMEQ_ENV
|
294
|
+
exit
|
295
|
+
end
|
296
|
+
|
297
|
+
if config.foreground
|
298
|
+
HomeQ::Base::Logging::Logger.instance.stdout
|
299
|
+
else
|
300
|
+
demonize
|
301
|
+
end
|
302
|
+
|
303
|
+
rescue OptionParser::ParseError => e
|
304
|
+
STDERR.puts e.message
|
305
|
+
exit(-1)
|
306
|
+
rescue SystemExit
|
307
|
+
exit
|
308
|
+
rescue Exception => e
|
309
|
+
raise
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Stop servers, queues and the control port. Wait for everthing
|
314
|
+
# to wind down, then exit.
|
315
|
+
def shutdown
|
316
|
+
stop_servers
|
317
|
+
stop_queues
|
318
|
+
@cp_server.stop if @cp_server
|
319
|
+
bye_if_done
|
320
|
+
end
|
321
|
+
|
322
|
+
# Wait for everything to wind down.
|
323
|
+
def bye_if_done
|
324
|
+
EventMachine::next_tick {
|
325
|
+
if (!@queues.find { |q| q.connected? } &&
|
326
|
+
!@servers.find { |s| s.connections.any? })
|
327
|
+
EventMachine::stop_event_loop
|
328
|
+
else
|
329
|
+
@queues.find { |q| q.connected? }.class
|
330
|
+
@servers.find { |s| s.connections.any? }.class
|
331
|
+
bye_if_done
|
332
|
+
end
|
333
|
+
}
|
334
|
+
end
|
335
|
+
|
336
|
+
# Start period tasks timer
|
337
|
+
def start_periodic_tasks
|
338
|
+
interval = config.period_task_interval || PERIOD_TASK_INTERVAL
|
339
|
+
EventMachine::add_periodic_timer(interval) {
|
340
|
+
sys.run_periodic_tasks
|
341
|
+
}
|
342
|
+
end
|
343
|
+
|
344
|
+
# Do any period tasks
|
345
|
+
def run_periodic_tasks
|
346
|
+
logger.debug4 {
|
347
|
+
"Running periodic tasks."
|
348
|
+
}
|
349
|
+
end
|
350
|
+
|
351
|
+
# Call each server in turn, telling it to start.
|
352
|
+
def start_servers
|
353
|
+
@servers.each { |s|
|
354
|
+
s.start
|
355
|
+
}
|
356
|
+
end
|
357
|
+
|
358
|
+
# Call each queue in turn, telling it to start.
|
359
|
+
def start_queues
|
360
|
+
@queues.each { |q|
|
361
|
+
q.start
|
362
|
+
if @handlers[q.queue_name]
|
363
|
+
q.handler = @handlers[q.queue_name]
|
364
|
+
end
|
365
|
+
}
|
366
|
+
end
|
367
|
+
|
368
|
+
def stop_servers
|
369
|
+
logger.debug {
|
370
|
+
"Stopping servers"
|
371
|
+
}
|
372
|
+
@servers.each { |s|
|
373
|
+
s.stop
|
374
|
+
}
|
375
|
+
end
|
376
|
+
|
377
|
+
def stop_queues
|
378
|
+
logger.debug {
|
379
|
+
"Stopping queues"
|
380
|
+
}
|
381
|
+
@queues.each { |q|
|
382
|
+
q.stop
|
383
|
+
}
|
384
|
+
end
|
385
|
+
|
386
|
+
def demonize
|
387
|
+
# Detach from controlling tty
|
388
|
+
parent = fork
|
389
|
+
exit! if parent
|
390
|
+
Process.setsid
|
391
|
+
|
392
|
+
# We want to be the grandchild. This is probably redundant in
|
393
|
+
# everything but some old weird SysV systems. But it seems to
|
394
|
+
# be the UNIX WAY(tm).
|
395
|
+
parent = fork
|
396
|
+
exit! if parent
|
397
|
+
|
398
|
+
store_pid
|
399
|
+
File.umask 0000
|
400
|
+
STDIN.reopen "/dev/null"
|
401
|
+
if options.log_file
|
402
|
+
STDOUT.reopen options.log_file, "a"
|
403
|
+
else
|
404
|
+
STDOUT.reopen "/dev/null", "a"
|
405
|
+
end
|
406
|
+
STDERR.reopen STDOUT
|
407
|
+
end
|
408
|
+
|
409
|
+
def store_pid
|
410
|
+
begin
|
411
|
+
filename = config.pid_file || "/var/log/hq_#{config.queue_name}.pid"
|
412
|
+
if File.exists?(filename)
|
413
|
+
die "Already running?! Pid file #{filename}."
|
414
|
+
end
|
415
|
+
File.open(filename, 'w') { |f|
|
416
|
+
f.puts Process.pid.to_s
|
417
|
+
}
|
418
|
+
rescue Errno::EACCES
|
419
|
+
die "Insufficient permissions to write pid file '#{filename}'"
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
def catch_signals
|
424
|
+
Signal.trap("INT") {
|
425
|
+
logger.info {
|
426
|
+
"Caught SIGINT; shutting down soon."
|
427
|
+
}
|
428
|
+
@state.stop
|
429
|
+
}
|
430
|
+
Signal.trap("USR1") {
|
431
|
+
@profiling ? stop_profiling : start_profiling
|
432
|
+
}
|
433
|
+
Signal.trap("USR2") {
|
434
|
+
logger.info {
|
435
|
+
"Caught SIGUSR2."
|
436
|
+
}
|
437
|
+
enable_debugging if !@debugging
|
438
|
+
debug_now
|
439
|
+
}
|
440
|
+
end
|
441
|
+
|
442
|
+
end # class System
|
443
|
+
|
444
|
+
end # module Base
|
445
|
+
|
446
|
+
end # HomeQ
|