run_rabbit_run 0.0.3
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/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/lib/run_rabbit_run/callbacks.rb +23 -0
- data/lib/run_rabbit_run/config/worker.rb +36 -0
- data/lib/run_rabbit_run/config.rb +54 -0
- data/lib/run_rabbit_run/master.rb +98 -0
- data/lib/run_rabbit_run/pid.rb +32 -0
- data/lib/run_rabbit_run/processes/base.rb +82 -0
- data/lib/run_rabbit_run/processes/master.rb +32 -0
- data/lib/run_rabbit_run/processes/signals.rb +56 -0
- data/lib/run_rabbit_run/processes/worker.rb +39 -0
- data/lib/run_rabbit_run/rabbitmq/system_messages.rb +37 -0
- data/lib/run_rabbit_run/rabbitmq.rb +50 -0
- data/lib/run_rabbit_run/tasks.rb +47 -0
- data/lib/run_rabbit_run/version.rb +3 -0
- data/lib/run_rabbit_run/worker.rb +33 -0
- data/lib/run_rabbit_run/workers.rb +112 -0
- data/lib/run_rabbit_run.rb +44 -0
- data/run_rabbit_run.gemspec +27 -0
- data/spec/dummy/Gemfile +3 -0
- data/spec/dummy/Rakefile +4 -0
- data/spec/dummy/config/rrr/development.rb +1 -0
- data/spec/dummy/config/rrr.rb +15 -0
- data/spec/dummy/workers/worker_name_1.rb +13 -0
- data/spec/dummy/workers/worker_name_2.rb +13 -0
- metadata +159 -0
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
log
|
19
|
+
.rvmrc
|
20
|
+
*.swp
|
21
|
+
dump.rdb
|
22
|
+
*.pid
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Arturs Kreipans
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# RunRabbitRun
|
2
|
+
|
3
|
+
git@github.com:fragallia/run_rabbit_run.git
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'run_rabbit_run'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install run_rabbit_run
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module RunRabbitRun
|
2
|
+
module Callbacks
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def define_callback *names
|
9
|
+
names.each do | name |
|
10
|
+
define_method name do | &block |
|
11
|
+
@callbacks ||= {}
|
12
|
+
@callbacks[name.to_sym] ||= []
|
13
|
+
@callbacks[name.to_sym] << block
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def call_callback name, *params
|
20
|
+
@callbacks[name.to_sym].each { | c | c.call *params } if @callbacks
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RunRabbitRun
|
2
|
+
module Config
|
3
|
+
class Worker
|
4
|
+
attr_accessor :options
|
5
|
+
|
6
|
+
def initialize(path, options = {})
|
7
|
+
@options = {
|
8
|
+
path: File.expand_path(path),
|
9
|
+
log_to_master: true,
|
10
|
+
processes: 1,
|
11
|
+
}.merge(options)
|
12
|
+
|
13
|
+
@options[:processes] = 1 unless @options[:processes].to_i > 0
|
14
|
+
|
15
|
+
raise "File not exists: #{@options[:path]}" unless File.exists?(@options[:path])
|
16
|
+
end
|
17
|
+
|
18
|
+
def options
|
19
|
+
@options ||= {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def name value
|
23
|
+
options[:name] = value
|
24
|
+
end
|
25
|
+
|
26
|
+
def processes value
|
27
|
+
options[:processes] = value > 0 ? value : 1
|
28
|
+
end
|
29
|
+
|
30
|
+
def log_to_master value
|
31
|
+
options[:log_to_master] = !!value
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'run_rabbit_run/config/worker'
|
2
|
+
|
3
|
+
module RunRabbitRun
|
4
|
+
module Config
|
5
|
+
extend self
|
6
|
+
|
7
|
+
attr_accessor :options
|
8
|
+
|
9
|
+
def load(application_path)
|
10
|
+
@options = {
|
11
|
+
application_path: application_path,
|
12
|
+
pid: "#{application_path}/tmp/pids/run_rabbit_run.pid",
|
13
|
+
environment: (ENV['RAKE_ENV'] || ENV['RAILS_ENV'] || 'development'),
|
14
|
+
log: "log/run_rabbit_run.log",
|
15
|
+
}
|
16
|
+
|
17
|
+
load_from_file "#{application_path}/config/rrr.rb"
|
18
|
+
load_from_file "#{application_path}/config/rrr/#{@options[:environment]}.rb"
|
19
|
+
|
20
|
+
options
|
21
|
+
end
|
22
|
+
|
23
|
+
def options
|
24
|
+
@options ||= {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def log value
|
28
|
+
options[:log] = File.expand_path(value)
|
29
|
+
end
|
30
|
+
|
31
|
+
def pid value
|
32
|
+
options[:pid] = File.expand_path(value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def worker name, path, options = {}, &block
|
36
|
+
worker = RunRabbitRun::Config::Worker.new(path, options)
|
37
|
+
worker.instance_exec &block if block_given?
|
38
|
+
|
39
|
+
self.options[:workers] ||= {}
|
40
|
+
self.options[:workers][name] = worker.options
|
41
|
+
end
|
42
|
+
|
43
|
+
def run *workers
|
44
|
+
options[:run] = workers
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def load_from_file(path)
|
50
|
+
instance_eval File.read(path), path
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'run_rabbit_run/workers'
|
2
|
+
require 'run_rabbit_run/rabbitmq'
|
3
|
+
require 'run_rabbit_run/rabbitmq/system_messages'
|
4
|
+
require 'run_rabbit_run/pid'
|
5
|
+
require 'run_rabbit_run/processes/master'
|
6
|
+
|
7
|
+
module RunRabbitRun
|
8
|
+
module Master
|
9
|
+
extend self
|
10
|
+
|
11
|
+
def master_process
|
12
|
+
@master_process ||= begin
|
13
|
+
master = RunRabbitRun::Processes::Master.new
|
14
|
+
master.pid = Pid.pid
|
15
|
+
|
16
|
+
master
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def start
|
21
|
+
master_process.start do
|
22
|
+
workers = RunRabbitRun::Workers.new
|
23
|
+
workers.start
|
24
|
+
|
25
|
+
add_periodic_timer 2 do
|
26
|
+
begin
|
27
|
+
workers.check unless exiting?
|
28
|
+
rescue => e
|
29
|
+
RunRabbitRun.logger.error e.message
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
before_exit do
|
34
|
+
workers.stop
|
35
|
+
end
|
36
|
+
|
37
|
+
before_reload do
|
38
|
+
workers.reload
|
39
|
+
end
|
40
|
+
|
41
|
+
on_system_message_received do | from, message, data |
|
42
|
+
begin
|
43
|
+
RunRabbitRun.logger.info "[master] got message [#{message}] from [#{from}] with data [#{data.inspect}]"
|
44
|
+
|
45
|
+
case message.to_sym
|
46
|
+
when :add_worker
|
47
|
+
workers.add(data['worker'])
|
48
|
+
when :remove_worker
|
49
|
+
workers.remove(data['worker'])
|
50
|
+
when :process_started
|
51
|
+
workers.worker(from.to_s).pid = data["pid"].to_i
|
52
|
+
end
|
53
|
+
rescue => e
|
54
|
+
RunRabbitRun.logger.error e.message
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
Pid.save(master_process.pid)
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_worker name
|
64
|
+
EventMachine.run do
|
65
|
+
rabbitmq = RunRabbitRun::Rabbitmq::Base.new
|
66
|
+
|
67
|
+
system_messages = RunRabbitRun::Rabbitmq::SystemMessages.new(rabbitmq)
|
68
|
+
system_messages.publish(:system, :master, :add_worker, { worker: name })
|
69
|
+
|
70
|
+
EventMachine.add_timer(2) do
|
71
|
+
rabbitmq.stop
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def remove_worker name
|
77
|
+
EventMachine.run do
|
78
|
+
rabbitmq = RunRabbitRun::Rabbitmq::Base.new
|
79
|
+
|
80
|
+
system_messages = RunRabbitRun::Rabbitmq::SystemMessages.new(rabbitmq)
|
81
|
+
system_messages.publish(:system, :master, :remove_worker, { worker: name })
|
82
|
+
|
83
|
+
EventMachine.add_timer(2) do
|
84
|
+
rabbitmq.stop
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def stop
|
90
|
+
RunRabbitRun::Processes::Signals.stop_signal(:master, master_process.pid)
|
91
|
+
Pid.remove
|
92
|
+
end
|
93
|
+
|
94
|
+
def reload
|
95
|
+
RunRabbitRun::Processes::Signals.reload_signal(:master, master_process.pid)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module RunRabbitRun
|
2
|
+
module Pid
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def remove
|
6
|
+
File.delete(path) if File.exists?(path)
|
7
|
+
end
|
8
|
+
|
9
|
+
def pid
|
10
|
+
File.open(path, 'r') { |file| file.read }.to_i if File.exists?(path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def save(pid)
|
14
|
+
create_directory_if_not_exists(File.dirname(path))
|
15
|
+
|
16
|
+
File.open(path, "w") {|file| file.puts(pid) }
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def path
|
22
|
+
raise "[ERROR] please specify the pid file path" unless RunRabbitRun.config[:pid]
|
23
|
+
|
24
|
+
RunRabbitRun.config[:pid]
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_directory_if_not_exists(dir)
|
28
|
+
FileUtils.mkdir_p(dir) unless File.exists?(dir)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'run_rabbit_run/callbacks'
|
2
|
+
require 'run_rabbit_run/processes/signals'
|
3
|
+
|
4
|
+
module RunRabbitRun
|
5
|
+
module Processes
|
6
|
+
class Base
|
7
|
+
include RunRabbitRun::Callbacks
|
8
|
+
|
9
|
+
define_callback :before_exit
|
10
|
+
define_callback :before_reload
|
11
|
+
|
12
|
+
attr_accessor :pid, :name
|
13
|
+
|
14
|
+
def initialize name
|
15
|
+
@name = name
|
16
|
+
end
|
17
|
+
|
18
|
+
def start &block
|
19
|
+
if RunRabbitRun::Processes::Signals.running? @pid
|
20
|
+
raise "The process [#{@name}] is already running"
|
21
|
+
end
|
22
|
+
|
23
|
+
RunRabbitRun.logger.info "[#{@name}] process starting"
|
24
|
+
|
25
|
+
@pid = fork do
|
26
|
+
$0 = "[ruby] [RunRabbitRun] #{@name}"
|
27
|
+
|
28
|
+
signals = []
|
29
|
+
|
30
|
+
Signal.trap(RunRabbitRun::SIGNAL_EXIT) { signals << RunRabbitRun::SIGNAL_EXIT }
|
31
|
+
Signal.trap(RunRabbitRun::SIGNAL_RELOAD) { signals << RunRabbitRun::SIGNAL_RELOAD }
|
32
|
+
|
33
|
+
EventMachine.run do
|
34
|
+
|
35
|
+
instance_exec &block
|
36
|
+
|
37
|
+
EventMachine::add_periodic_timer( 0.5 ) do
|
38
|
+
if signals.include?( RunRabbitRun::SIGNAL_RELOAD )
|
39
|
+
signals.delete( RunRabbitRun::SIGNAL_RELOAD )
|
40
|
+
|
41
|
+
call_callback :before_reload
|
42
|
+
end
|
43
|
+
if signals.include?( RunRabbitRun::SIGNAL_EXIT )
|
44
|
+
@exiting = true
|
45
|
+
|
46
|
+
call_callback :before_exit
|
47
|
+
EventMachine::add_timer( 10 ) do
|
48
|
+
EventMachine.stop { exit }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
RunRabbitRun.logger.info "[#{@name}] process finished"
|
55
|
+
end
|
56
|
+
|
57
|
+
Process.detach(@pid)
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
def exiting?
|
62
|
+
@exiting ||= false
|
63
|
+
end
|
64
|
+
|
65
|
+
def guid
|
66
|
+
"#{@name}-#{@pid}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_timer seconds, &block
|
70
|
+
EventMachine::add_timer( seconds ) do
|
71
|
+
block.call
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_periodic_timer seconds, &block
|
76
|
+
EventMachine::add_periodic_timer( seconds ) do
|
77
|
+
block.call
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'run_rabbit_run/processes/base'
|
2
|
+
|
3
|
+
module RunRabbitRun
|
4
|
+
|
5
|
+
module Processes
|
6
|
+
class Master < Base
|
7
|
+
|
8
|
+
define_callback :on_system_message_received
|
9
|
+
|
10
|
+
def initialize name = :master
|
11
|
+
super name
|
12
|
+
end
|
13
|
+
|
14
|
+
def start &block
|
15
|
+
super do
|
16
|
+
instance_exec &block
|
17
|
+
|
18
|
+
rabbitmq = RunRabbitRun::Rabbitmq::Base.new
|
19
|
+
system_messages = RunRabbitRun::Rabbitmq::SystemMessages.new(rabbitmq)
|
20
|
+
|
21
|
+
system_messages.subscribe "master.#" do | headers, payload |
|
22
|
+
call_callback :on_system_message_received, payload["from"].to_sym, payload["message"].to_sym, payload["data"]
|
23
|
+
end
|
24
|
+
|
25
|
+
before_exit do
|
26
|
+
rabbitmq.stop
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module RunRabbitRun
|
2
|
+
module Processes
|
3
|
+
module Signals
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def running? pid
|
7
|
+
return false unless pid
|
8
|
+
|
9
|
+
begin
|
10
|
+
Process.getpgid(pid.to_i )
|
11
|
+
|
12
|
+
return true
|
13
|
+
rescue Errno::ESRCH
|
14
|
+
rescue Exception => e
|
15
|
+
RunRabbitRun.logger.error "#{e}, #{e.backtrace.join("\n")}"
|
16
|
+
end
|
17
|
+
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
21
|
+
def kill_signal name, pid
|
22
|
+
send_signal name, pid, RunRabbitRun::SIGNAL_KILL
|
23
|
+
end
|
24
|
+
|
25
|
+
def stop_signal name, pid
|
26
|
+
send_signal name, pid, RunRabbitRun::SIGNAL_EXIT
|
27
|
+
end
|
28
|
+
|
29
|
+
def reload_signal name, pid
|
30
|
+
send_signal name, pid, RunRabbitRun::SIGNAL_RELOAD
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def send_signal name, pid, signal
|
36
|
+
if running? pid
|
37
|
+
RunRabbitRun.logger.info "[#{name}] send #{signal_name(signal)} signal to process"
|
38
|
+
Process.kill(signal, pid)
|
39
|
+
else
|
40
|
+
RunRabbitRun.logger.debug "[#{name}] is not running"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def signal_name code
|
45
|
+
case code
|
46
|
+
when 'QUIT'
|
47
|
+
'exit'
|
48
|
+
when 'USR1'
|
49
|
+
'reload'
|
50
|
+
when 'KILL'
|
51
|
+
'kill'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'run_rabbit_run/processes/base'
|
2
|
+
|
3
|
+
module RunRabbitRun
|
4
|
+
module Processes
|
5
|
+
class Worker < Base
|
6
|
+
|
7
|
+
def initialize name, options
|
8
|
+
@options = options
|
9
|
+
|
10
|
+
super name
|
11
|
+
end
|
12
|
+
|
13
|
+
def start &block
|
14
|
+
super do
|
15
|
+
instance_exec &block if block_given?
|
16
|
+
|
17
|
+
rabbitmq = RunRabbitRun::Rabbitmq::Base.new
|
18
|
+
system_messages = RunRabbitRun::Rabbitmq::SystemMessages.new(rabbitmq)
|
19
|
+
|
20
|
+
system_messages.publish(@name, :master, :process_started, { pid: Process.pid } )
|
21
|
+
|
22
|
+
rabbitmq.on_message_received do | queue |
|
23
|
+
system_messages.publish(@name, :master, :message_received, { queue: queue.name } ) if @options[:log_to_master]
|
24
|
+
end
|
25
|
+
rabbitmq.on_message_processed do | queue |
|
26
|
+
system_messages.publish(@name, :master, :message_processed, { queue: queue.name } ) if @options[:log_to_master]
|
27
|
+
end
|
28
|
+
|
29
|
+
rabbitmq.instance_eval File.read(@options[:path]), @options[:path]
|
30
|
+
|
31
|
+
before_exit do
|
32
|
+
system_messages.publish(@name, :master, :process_quit)
|
33
|
+
rabbitmq.stop
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RunRabbitRun
|
2
|
+
module Rabbitmq
|
3
|
+
class SystemMessages
|
4
|
+
def initialize(rabbitmq)
|
5
|
+
@rabbitmq = rabbitmq
|
6
|
+
end
|
7
|
+
|
8
|
+
def subscribe routing_key, &block
|
9
|
+
system_queue.bind(system_exchange, routing_key: "profile.#{RunRabbitRun.config[:environment]}.#{routing_key}")
|
10
|
+
system_queue.subscribe do | headers, payload |
|
11
|
+
block.call(headers, JSON.parse(payload))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def publish from, target, message, data = {}
|
16
|
+
system_exchange.publish(
|
17
|
+
JSON.generate({
|
18
|
+
from: from,
|
19
|
+
message: message,
|
20
|
+
data: { time: Time.now.to_f }.merge(data)
|
21
|
+
}),
|
22
|
+
routing_key: "profile.#{RunRabbitRun.config[:environment]}.#{target}")
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def system_queue
|
28
|
+
@system_queue ||= @rabbitmq.channel.queue("profile.#{RunRabbitRun.config[:environment]}", auto_delete: false)
|
29
|
+
end
|
30
|
+
|
31
|
+
def system_exchange
|
32
|
+
@system_exchange ||= @rabbitmq.channel.topic("runrabbitrun.system", durable: true)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'run_rabbit_run/callbacks'
|
2
|
+
|
3
|
+
module RunRabbitRun
|
4
|
+
module Rabbitmq
|
5
|
+
class Base
|
6
|
+
include RunRabbitRun::Callbacks
|
7
|
+
|
8
|
+
define_callback :on_message_received
|
9
|
+
define_callback :on_message_processed
|
10
|
+
|
11
|
+
def subscribe(queue, options = {}, &block)
|
12
|
+
opts = options.dup
|
13
|
+
time_logging = opts.delete(:time_logging) || false
|
14
|
+
|
15
|
+
queue.subscribe do | header, payload |
|
16
|
+
RunRabbitRun.logger.info "[#{queue.name}] [#{Time.now.to_f}] started" if time_logging
|
17
|
+
call_callback :on_message_received, queue
|
18
|
+
|
19
|
+
instance_exec(header, JSON.parse(payload), &block)
|
20
|
+
|
21
|
+
call_callback :on_message_processed, queue
|
22
|
+
RunRabbitRun.logger.info "[#{queue.name}] [#{Time.now.to_f}] finished" if time_logging
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def publish(queue, data)
|
27
|
+
exchange.publish JSON.generate(data), :routing_key => queue.name
|
28
|
+
end
|
29
|
+
|
30
|
+
def connection
|
31
|
+
@connection ||= AMQP.connect(host: '127.0.0.1', username: "guest", password: "guest")
|
32
|
+
end
|
33
|
+
|
34
|
+
def channel
|
35
|
+
@channel ||= AMQP::Channel.new(connection, AMQP::Channel.next_channel_id, auto_recovery: true)
|
36
|
+
end
|
37
|
+
|
38
|
+
def exchange
|
39
|
+
@exchange ||= channel.direct('')
|
40
|
+
end
|
41
|
+
|
42
|
+
def stop
|
43
|
+
connection.close {
|
44
|
+
EventMachine.stop { exit }
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "run_rabbit_run"
|
2
|
+
|
3
|
+
namespace :rrr do
|
4
|
+
desc 'Starts profile workers'
|
5
|
+
task start: [ :config ] do
|
6
|
+
RunRabbitRun::Master.start
|
7
|
+
end
|
8
|
+
|
9
|
+
desc 'Stops profile workers'
|
10
|
+
task stop: [ :config ] do
|
11
|
+
RunRabbitRun::Master.stop
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'Reloads config, stops old workers and runs new with new config'
|
15
|
+
task reload: [ :config ] do
|
16
|
+
RunRabbitRun::Master.reload
|
17
|
+
end
|
18
|
+
|
19
|
+
namespace :worker do
|
20
|
+
desc 'Adds one process for given worker'
|
21
|
+
task :add, [ :worker_name ] => [ :config ] do | t, args |
|
22
|
+
raise 'Please specify worker name' unless args[:worker_name]
|
23
|
+
RunRabbitRun::Master.add_worker(args[:worker_name])
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Stops one process for given worker'
|
27
|
+
task :remove, [ :worker_name ] => [ :config ] do | t, args |
|
28
|
+
raise 'Please specify worker name' unless args[:worker_name]
|
29
|
+
RunRabbitRun::Master.remove_worker(args[:worker_name])
|
30
|
+
end
|
31
|
+
|
32
|
+
task :new, [ :worker_name, :worker_guid ] => [ :config ] do | t, args |
|
33
|
+
raise 'Please specify worker name' unless args[:worker_name]
|
34
|
+
raise 'Please specify worker guid' unless args[:worker_guid]
|
35
|
+
|
36
|
+
require 'run_rabbit_run/processes/worker'
|
37
|
+
|
38
|
+
options = RunRabbitRun.config[:workers][args[:worker_name].to_sym]
|
39
|
+
|
40
|
+
RunRabbitRun::Processes::Worker.new(args[:worker_guid], options).start
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
task :config do
|
45
|
+
RunRabbitRun.load_config(Rake.original_dir)
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'run_rabbit_run/processes/signals'
|
2
|
+
|
3
|
+
module RunRabbitRun
|
4
|
+
class Worker
|
5
|
+
attr_accessor :name, :guid, :pid, :status
|
6
|
+
def initialize(name, guid)
|
7
|
+
@name, @guid, @pid = name, guid, nil
|
8
|
+
|
9
|
+
@status = :unknown
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
#TODO get path for bundle
|
14
|
+
success = system("RAKE_ENV=#{RunRabbitRun.config[:environment]} bundle exec rake rrr:worker:new[#{@name},#{@guid}]")
|
15
|
+
end
|
16
|
+
|
17
|
+
def kill
|
18
|
+
RunRabbitRun::Processes::Signals.kill_signal(@guid, @pid)
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop
|
22
|
+
RunRabbitRun::Processes::Signals.stop_signal(@guid, @pid)
|
23
|
+
end
|
24
|
+
|
25
|
+
def reload
|
26
|
+
RunRabbitRun::Processes::Signals.reload_signal(@guid, @pid)
|
27
|
+
end
|
28
|
+
|
29
|
+
def running?
|
30
|
+
RunRabbitRun::Processes::Signals.running? @pid
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module RunRabbitRun
|
2
|
+
require 'run_rabbit_run/worker'
|
3
|
+
|
4
|
+
class Workers
|
5
|
+
def initialize
|
6
|
+
@workers = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def worker(guid)
|
10
|
+
@workers.each do | name, workers |
|
11
|
+
workers.each do | current_guid, worker |
|
12
|
+
return worker if current_guid == guid
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def check
|
20
|
+
@workers.each do | name, workers |
|
21
|
+
workers.each do | guid, worker |
|
22
|
+
worker.run unless worker.running?
|
23
|
+
end
|
24
|
+
diff = RunRabbitRun.config[:workers][name][:processes] - workers.size
|
25
|
+
diff.times{ run_new_worker name } if diff > 0
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def add name
|
30
|
+
run_new_worker name
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove name
|
34
|
+
guid = @workers[name.to_sym].keys.sort.first
|
35
|
+
worker = @workers[name.to_sym][guid]
|
36
|
+
|
37
|
+
worker.stop
|
38
|
+
|
39
|
+
sleep 1
|
40
|
+
|
41
|
+
if worker.running?
|
42
|
+
sleep 4
|
43
|
+
worker.kill if worker.running?
|
44
|
+
end
|
45
|
+
|
46
|
+
@workers[name.to_sym].delete(guid)
|
47
|
+
end
|
48
|
+
|
49
|
+
def start
|
50
|
+
RunRabbitRun.config[:run].each do | name |
|
51
|
+
RunRabbitRun.config[:workers][name][:processes].times do | n |
|
52
|
+
run_new_worker name
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def stop
|
58
|
+
# try to stop gracefully
|
59
|
+
@workers.each { | name, workers | workers.each { | guid, worker | worker.stop } }
|
60
|
+
|
61
|
+
sleep 1
|
62
|
+
|
63
|
+
@workers.each do | name, workers |
|
64
|
+
workers.each do | guid, worker |
|
65
|
+
if worker.running?
|
66
|
+
sleep 4
|
67
|
+
self.kill # kill workers which are still running
|
68
|
+
return
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
@workers = {}
|
74
|
+
end
|
75
|
+
|
76
|
+
def kill
|
77
|
+
@workers.each { | name, workers | workers.each { | guid, worker | worker.kill if worker.running? } }
|
78
|
+
|
79
|
+
@workers = {}
|
80
|
+
end
|
81
|
+
|
82
|
+
def reload
|
83
|
+
# reload the config file
|
84
|
+
RunRabbitRun.load_config( RunRabbitRun.config[:application_path] )
|
85
|
+
|
86
|
+
self.stop
|
87
|
+
self.start
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def run_new_worker name
|
93
|
+
name = name.to_sym
|
94
|
+
guid = generate_guid(name)
|
95
|
+
worker = RunRabbitRun::Worker.new(name, guid)
|
96
|
+
|
97
|
+
@workers[name] ||= {}
|
98
|
+
@workers[name][guid] = worker
|
99
|
+
|
100
|
+
worker.run
|
101
|
+
end
|
102
|
+
|
103
|
+
def generate_guid name
|
104
|
+
last_guid = @workers[name].keys.sort.last if @workers[name]
|
105
|
+
|
106
|
+
index = (last_guid ? last_guid.split('-').last.to_i : 0) + 1
|
107
|
+
|
108
|
+
"#{name}-#{index}"
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "run_rabbit_run/version"
|
2
|
+
|
3
|
+
require 'amqp'
|
4
|
+
require 'bson'
|
5
|
+
require 'json'
|
6
|
+
require 'logger'
|
7
|
+
|
8
|
+
module RunRabbitRun
|
9
|
+
require 'run_rabbit_run/master'
|
10
|
+
require 'run_rabbit_run/config'
|
11
|
+
|
12
|
+
extend self
|
13
|
+
|
14
|
+
SIGNAL_EXIT = 'QUIT'
|
15
|
+
SIGNAL_RELOAD = 'USR1'
|
16
|
+
SIGNAL_KILL = 'KILL'
|
17
|
+
|
18
|
+
def load_config application_path
|
19
|
+
@@config = RunRabbitRun::Config.load(application_path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def config
|
23
|
+
@@config
|
24
|
+
end
|
25
|
+
|
26
|
+
def logger
|
27
|
+
@@logger ||= begin
|
28
|
+
path = self.config[:log]
|
29
|
+
|
30
|
+
FileUtils.mkdir_p(File.dirname(path)) unless File.exists?(File.dirname(path))
|
31
|
+
|
32
|
+
logger = Logger.new(path, 10, 1024000)
|
33
|
+
|
34
|
+
if self.config[:environment] == 'development'
|
35
|
+
logger.level = Logger::DEBUG
|
36
|
+
else
|
37
|
+
logger.level = Logger::INFO
|
38
|
+
end
|
39
|
+
|
40
|
+
logger
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
# include gem version
|
5
|
+
require 'run_rabbit_run/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |gem|
|
8
|
+
gem.authors = ["Arturs Kreipans"]
|
9
|
+
gem.email = ["arturs.kreipans@gmail.com"]
|
10
|
+
gem.description = %q{RunRabbitRun gem lets to run and manage multiple ruby processes for RabbitMQ}
|
11
|
+
gem.summary = %q{RunRabbitRun gem lets to run and manage multiple ruby processes for RabbitMQ}
|
12
|
+
gem.homepage = ""
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($\)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.name = "run_rabbit_run"
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.version = RunRabbitRun::VERSION
|
20
|
+
|
21
|
+
gem.add_dependency "rake"
|
22
|
+
gem.add_dependency "bson_ext"
|
23
|
+
gem.add_dependency "amqp"
|
24
|
+
|
25
|
+
gem.add_development_dependency 'pry'
|
26
|
+
gem.add_development_dependency 'pry-remote'
|
27
|
+
end
|
data/spec/dummy/Gemfile
ADDED
data/spec/dummy/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
run :worker1, :worker2
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'run_rabbit_run'
|
2
|
+
|
3
|
+
#TODO working_directory '/path/to/working/directory'
|
4
|
+
|
5
|
+
log "log/run_rabbit_run.log"
|
6
|
+
pid "tmp/pids/run_rabbit_run.pid"
|
7
|
+
|
8
|
+
worker :worker1, 'workers/worker_name_1.rb', processes: 1
|
9
|
+
|
10
|
+
worker :worker2, 'workers/worker_name_2.rb' do
|
11
|
+
name 'Worker name 2'
|
12
|
+
log_to_master true
|
13
|
+
|
14
|
+
processes 1
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
output = channel.queue('output', auto_delete: false)
|
2
|
+
input = channel.queue('input', auto_delete: false)
|
3
|
+
|
4
|
+
publish(output, {some: 'data'})
|
5
|
+
|
6
|
+
subscribe(output, time_logging: true) do | header, data |
|
7
|
+
RunRabbitRun.logger.info data.inspect
|
8
|
+
publish(input, {received: 'data'})
|
9
|
+
end
|
10
|
+
|
11
|
+
subscribe(input) do | header, data |
|
12
|
+
RunRabbitRun.logger.info data.inspect
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
output = channel.queue('output2', auto_delete: false)
|
2
|
+
input = channel.queue('input2', auto_delete: false)
|
3
|
+
|
4
|
+
publish(output, {some: 'data'})
|
5
|
+
|
6
|
+
subscribe(output) do | header, data |
|
7
|
+
RunRabbitRun.logger.info data.inspect
|
8
|
+
publish(input, {received: 'data'})
|
9
|
+
end
|
10
|
+
|
11
|
+
subscribe(input) do | header, data |
|
12
|
+
RunRabbitRun.logger.info data.inspect
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: run_rabbit_run
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Arturs Kreipans
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bson_ext
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: amqp
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: pry
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: pry-remote
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: RunRabbitRun gem lets to run and manage multiple ruby processes for RabbitMQ
|
95
|
+
email:
|
96
|
+
- arturs.kreipans@gmail.com
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- .gitignore
|
102
|
+
- Gemfile
|
103
|
+
- LICENSE
|
104
|
+
- README.md
|
105
|
+
- Rakefile
|
106
|
+
- lib/run_rabbit_run.rb
|
107
|
+
- lib/run_rabbit_run/callbacks.rb
|
108
|
+
- lib/run_rabbit_run/config.rb
|
109
|
+
- lib/run_rabbit_run/config/worker.rb
|
110
|
+
- lib/run_rabbit_run/master.rb
|
111
|
+
- lib/run_rabbit_run/pid.rb
|
112
|
+
- lib/run_rabbit_run/processes/base.rb
|
113
|
+
- lib/run_rabbit_run/processes/master.rb
|
114
|
+
- lib/run_rabbit_run/processes/signals.rb
|
115
|
+
- lib/run_rabbit_run/processes/worker.rb
|
116
|
+
- lib/run_rabbit_run/rabbitmq.rb
|
117
|
+
- lib/run_rabbit_run/rabbitmq/system_messages.rb
|
118
|
+
- lib/run_rabbit_run/tasks.rb
|
119
|
+
- lib/run_rabbit_run/version.rb
|
120
|
+
- lib/run_rabbit_run/worker.rb
|
121
|
+
- lib/run_rabbit_run/workers.rb
|
122
|
+
- run_rabbit_run.gemspec
|
123
|
+
- spec/dummy/Gemfile
|
124
|
+
- spec/dummy/Rakefile
|
125
|
+
- spec/dummy/config/rrr.rb
|
126
|
+
- spec/dummy/config/rrr/development.rb
|
127
|
+
- spec/dummy/workers/worker_name_1.rb
|
128
|
+
- spec/dummy/workers/worker_name_2.rb
|
129
|
+
homepage: ''
|
130
|
+
licenses: []
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ! '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ! '>='
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
requirements: []
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 1.8.24
|
150
|
+
signing_key:
|
151
|
+
specification_version: 3
|
152
|
+
summary: RunRabbitRun gem lets to run and manage multiple ruby processes for RabbitMQ
|
153
|
+
test_files:
|
154
|
+
- spec/dummy/Gemfile
|
155
|
+
- spec/dummy/Rakefile
|
156
|
+
- spec/dummy/config/rrr.rb
|
157
|
+
- spec/dummy/config/rrr/development.rb
|
158
|
+
- spec/dummy/workers/worker_name_1.rb
|
159
|
+
- spec/dummy/workers/worker_name_2.rb
|