rabbit-wq 1.9.0 → 2.0.0
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.
- checksums.yaml +4 -4
- data/bin/rabbit-wq +2 -2
- data/lib/rabbit_wq/cli.rb +5 -120
- data/lib/rabbit_wq/configuration.rb +22 -77
- data/lib/rabbit_wq/invalid_work_error.rb +5 -0
- data/lib/rabbit_wq/message_handler.rb +19 -5
- data/lib/rabbit_wq/server.rb +46 -69
- data/lib/rabbit_wq/version.rb +1 -1
- data/lib/rabbit_wq/work.rb +4 -4
- data/lib/rabbit_wq/work_logger.rb +1 -1
- data/lib/rabbit_wq/{logging.rb → work_logging.rb} +1 -8
- data/lib/rabbit_wq.rb +34 -29
- data/rabbit-wq.gemspec +1 -1
- metadata +13 -9
- data/lib/ansi.rb +0 -36
- data/lib/rabbit_wq/server_daemon.rb +0 -149
- data/lib/rabbit_wq/server_logging.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8146dc0247a3db1e510b8c6205e8ede3892667a
|
4
|
+
data.tar.gz: f141d450c09d9b0a925ce0f398f45aadfd1430f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f62f6087f74838fb3b4b3f02a63c1e36663a714f192731203dafabc6f86c506d488fd43f14c270f1893094da87462aed35202592c07ca63d46708d3b80fde6d
|
7
|
+
data.tar.gz: 76bdc1c54aba7299d5b7ba993b5fe5782bd508e8e7450a915f226c3c91938a20974596b55ec5d3a0ce4390426b89161985c7318644964e1b1f0c7056b0efbad6
|
data/bin/rabbit-wq
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require 'rabbit_wq
|
3
|
-
RabbitWQ::Cli.
|
2
|
+
require 'rabbit_wq'
|
3
|
+
RabbitWQ::Cli.start
|
data/lib/rabbit_wq/cli.rb
CHANGED
@@ -1,129 +1,14 @@
|
|
1
|
-
require '
|
2
|
-
require 'rabbit_wq'
|
3
|
-
require 'trollop'
|
4
|
-
require 'yell'
|
1
|
+
require 'servitude'
|
5
2
|
|
6
3
|
module RabbitWQ
|
7
|
-
class Cli
|
4
|
+
class Cli < ::Servitude::Cli::Service
|
8
5
|
|
9
|
-
|
10
|
-
:options
|
6
|
+
no_commands do
|
11
7
|
|
12
|
-
|
13
|
-
|
14
|
-
start
|
15
|
-
status
|
16
|
-
stop
|
17
|
-
)
|
18
|
-
|
19
|
-
DEFAULT_CONFIG_PATH = "/etc/#{APP_ID}/#{APP_ID}.conf"
|
20
|
-
DEFAULT_LOG_PATH = "/var/log/#{APP_ID}/#{APP_ID}.log"
|
21
|
-
DEFAULT_PID_PATH = "/var/run/#{APP_ID}/#{APP_ID}.pid"
|
22
|
-
|
23
|
-
def initialize( args )
|
24
|
-
Trollop::options do
|
25
|
-
version VERSION_COPYRIGHT
|
26
|
-
banner <<-EOS
|
27
|
-
#{APP_NAME} #{VERSION_COPYRIGHT}
|
28
|
-
|
29
|
-
Usage:
|
30
|
-
#{APP_ID} [command] [options]
|
31
|
-
|
32
|
-
commands:
|
33
|
-
#{SUB_COMMANDS.map { |sub_cmd| " #{sub_cmd}" }.join( "\n" )}
|
34
|
-
|
35
|
-
(For help with a command: #{APP_ID} [command] -h)
|
36
|
-
|
37
|
-
options:
|
38
|
-
EOS
|
39
|
-
stop_on SUB_COMMANDS
|
40
|
-
end
|
41
|
-
|
42
|
-
# Get the sub-command and its options
|
43
|
-
#
|
44
|
-
@cmd = ARGV.shift || ''
|
45
|
-
@options = case( cmd )
|
46
|
-
when "restart"
|
47
|
-
Trollop::options do
|
48
|
-
opt :config, "The path for the config file", :type => String, :short => '-c', :default => DEFAULT_CONFIG_PATH
|
49
|
-
opt :log_level, "The log level", :type => String, :default => 'info'
|
50
|
-
opt :log, "The path for the log file", :type => String, :short => '-l', :default => DEFAULT_LOG_PATH
|
51
|
-
opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
|
52
|
-
opt :threads, "The number of threads", :type => Integer, :short => '-t'
|
53
|
-
end
|
54
|
-
when "start"
|
55
|
-
Trollop::options do
|
56
|
-
opt :config, "The path for the config file", :type => String, :short => '-c', :default => DEFAULT_CONFIG_PATH
|
57
|
-
opt :interactive, "Execute the server in interactive mode", :short => '-i'
|
58
|
-
opt :log_level, "The log level", :type => String, :default => 'info'
|
59
|
-
opt :log, "The path for the log file", :type => String, :short => '-l', :default => DEFAULT_LOG_PATH
|
60
|
-
opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
|
61
|
-
opt :threads, "The number of threads", :type => Integer, :short => '-t'
|
62
|
-
end
|
63
|
-
when "status"
|
64
|
-
Trollop::options do
|
65
|
-
opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
|
66
|
-
opt :quiet, "Do not prompt to remove an old PID file", :type => :boolean, :default => false, :short => '-q'
|
67
|
-
end
|
68
|
-
when "stop"
|
69
|
-
Trollop::options do
|
70
|
-
opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
|
71
|
-
opt :quiet, "Do not prompt to remove an old PID file", :type => :boolean, :default => false, :short => '-q'
|
72
|
-
end
|
73
|
-
else
|
74
|
-
Trollop::die "unknown command #{cmd.inspect}"
|
75
|
-
end
|
76
|
-
|
77
|
-
if cmd == 'start'
|
78
|
-
unless options[:interactive]
|
79
|
-
Trollop::die( :config, "is required when running as daemon" ) unless options[:config]
|
80
|
-
Trollop::die( :log, "is required when running as daemon" ) unless options[:log]
|
81
|
-
Trollop::die( :pid, "is required when running as daemon" ) unless options[:pid]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
if %w(restart status stop).include?( cmd )
|
86
|
-
Trollop::die( :pid, "is required" ) unless options[:pid]
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def run
|
91
|
-
send( cmd )
|
92
|
-
end
|
93
|
-
|
94
|
-
protected
|
95
|
-
|
96
|
-
def start
|
97
|
-
if options[:interactive]
|
98
|
-
start_interactive
|
99
|
-
else
|
100
|
-
start_daemon
|
8
|
+
def configuration_class
|
9
|
+
RabbitWQ::Configuration
|
101
10
|
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def start_interactive
|
105
|
-
server = RabbitWQ::Server.new( options.merge( log: nil ))
|
106
|
-
server.start
|
107
|
-
end
|
108
|
-
|
109
|
-
def start_daemon
|
110
|
-
server = RabbitWQ::ServerDaemon.new( options )
|
111
|
-
server.start
|
112
|
-
end
|
113
|
-
|
114
|
-
def stop
|
115
|
-
server = RabbitWQ::ServerDaemon.new( options )
|
116
|
-
server.stop
|
117
|
-
end
|
118
|
-
|
119
|
-
def restart
|
120
|
-
stop
|
121
|
-
start_daemon
|
122
|
-
end
|
123
11
|
|
124
|
-
def status
|
125
|
-
result = RabbitWQ::ServerDaemon.new( options ).status
|
126
|
-
at_exit { exit result }
|
127
12
|
end
|
128
13
|
|
129
14
|
end
|
@@ -1,83 +1,28 @@
|
|
1
|
-
require '
|
1
|
+
require 'servitude'
|
2
2
|
|
3
3
|
module RabbitWQ
|
4
|
-
class Configuration
|
5
|
-
|
6
|
-
def self.
|
7
|
-
|
8
|
-
delayed_exchange_prefix
|
9
|
-
delayed_queue_prefix
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def self.from_file( file_path )
|
27
|
-
options = Oj.load( File.read( file_path ))
|
28
|
-
RabbitWQ.configuration = Configuration.new
|
29
|
-
|
30
|
-
attributes.each do |c|
|
31
|
-
if options[c]
|
32
|
-
RabbitWQ.configuration.send( :"#{c}=", options[c] )
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def delayed_exchange_prefix
|
38
|
-
@delayed_exchange_prefix || 'work-delay'
|
39
|
-
end
|
40
|
-
|
41
|
-
def delayed_queue_prefix
|
42
|
-
@delayed_queue_prefix || 'work-delay'
|
43
|
-
end
|
44
|
-
|
45
|
-
def env
|
46
|
-
@env || 'production'
|
47
|
-
end
|
48
|
-
|
49
|
-
def error_queue
|
50
|
-
@error_queue || 'work-error'
|
51
|
-
end
|
52
|
-
|
53
|
-
def time_zone
|
54
|
-
@time_zone || 'UTC'
|
55
|
-
end
|
56
|
-
|
57
|
-
def work_exchange
|
58
|
-
@work_exchange || 'work'
|
59
|
-
end
|
60
|
-
|
61
|
-
def work_exchange_type
|
62
|
-
@work_exchange_type || 'fanout'
|
63
|
-
end
|
64
|
-
|
65
|
-
def work_log_level
|
66
|
-
@work_log_level || 'info'
|
67
|
-
end
|
68
|
-
|
69
|
-
def work_log_path
|
70
|
-
@work_log_path || '/var/log/rabbit-wq/rabbit-wq-work.log'
|
71
|
-
end
|
72
|
-
|
73
|
-
def work_publish_queue
|
74
|
-
@work_publish_queue || 'work'
|
75
|
-
end
|
76
|
-
|
77
|
-
def work_subscribe_queue
|
78
|
-
@work_subscribe_queue || 'work'
|
4
|
+
class Configuration < Servitude::Configuration
|
5
|
+
|
6
|
+
def self.defaults
|
7
|
+
{
|
8
|
+
delayed_exchange_prefix: 'work-delay',
|
9
|
+
delayed_queue_prefix: 'work-delay',
|
10
|
+
env: 'production',
|
11
|
+
error_queue: 'work-error',
|
12
|
+
log: "/var/log/rabbit-wq/#{RabbitWQ.process_name}.log",
|
13
|
+
log_level: 'info',
|
14
|
+
pid: "/var/run/rabbit-wq/#{RabbitWQ.process_name}.pid",
|
15
|
+
supervision_retry_timeout_in_seconds: 1,
|
16
|
+
threads: 1,
|
17
|
+
time_zone: 'UTC',
|
18
|
+
work_exchange: 'work',
|
19
|
+
work_exchange_type: 'fanout',
|
20
|
+
work_log_level: 'info',
|
21
|
+
work_log_path: '/var/log/rabbit-wq/rabbit-wq-work.log',
|
22
|
+
work_publish_queue: 'work',
|
23
|
+
work_subscribe_queue: 'work'
|
24
|
+
}
|
79
25
|
end
|
80
26
|
|
81
27
|
end
|
82
|
-
|
83
28
|
end
|
@@ -1,25 +1,27 @@
|
|
1
1
|
require 'celluloid/autostart'
|
2
|
+
require 'servitude'
|
2
3
|
require 'yaml'
|
3
4
|
|
4
5
|
module RabbitWQ
|
5
6
|
class MessageHandler
|
6
7
|
|
7
8
|
include Celluloid
|
8
|
-
include Logging
|
9
9
|
include Queues
|
10
|
+
include Servitude::Logging
|
11
|
+
include WorkLogging
|
10
12
|
|
11
13
|
REQUEUE = true
|
12
14
|
|
13
15
|
def call( options )
|
14
|
-
Time.zone =
|
16
|
+
Time.zone = Servitude.configuration.time_zone
|
15
17
|
|
16
18
|
channel = options[:channel]
|
17
19
|
delivery_info = options[:delivery_info]
|
18
20
|
metadata = options[:metadata]
|
19
21
|
payload = options[:payload]
|
20
22
|
|
21
|
-
worker =
|
22
|
-
info
|
23
|
+
worker = deserialize_worker( payload )
|
24
|
+
info Rainbow( "WORKER [#{worker.object_id}] " + worker.inspect ).yellow
|
23
25
|
handle_work( worker, payload )
|
24
26
|
try_on_success_callback( worker )
|
25
27
|
channel.ack delivery_info.delivery_tag
|
@@ -29,6 +31,18 @@ module RabbitWQ
|
|
29
31
|
|
30
32
|
protected
|
31
33
|
|
34
|
+
def deserialize_worker( payload )
|
35
|
+
YAML::load( payload ).tap do |worker|
|
36
|
+
unless worker.is_a?( RabbitWQ::Worker )
|
37
|
+
raise ArgumentError, "Worker of type #{worker.class.name} is not a valid worker (not a descendent of #{RabbitWQ::Worker.name})"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
rescue => e
|
41
|
+
raise RabbitWQ::InvalidWorkError,
|
42
|
+
"#{e.message} -- #{e.class.name}",
|
43
|
+
e.backtrace
|
44
|
+
end
|
45
|
+
|
32
46
|
def handle_work( worker, payload )
|
33
47
|
unless worker.enabled?
|
34
48
|
if worker.error_on_disabled?
|
@@ -106,7 +120,7 @@ module RabbitWQ
|
|
106
120
|
end
|
107
121
|
|
108
122
|
def requeue( channel, delivery_info, e=nil )
|
109
|
-
info
|
123
|
+
info Rainbow( 'REQUEUE ' + e.message ).yellow
|
110
124
|
channel.reject delivery_info.delivery_tag, REQUEUE
|
111
125
|
end
|
112
126
|
|
data/lib/rabbit_wq/server.rb
CHANGED
@@ -1,37 +1,42 @@
|
|
1
1
|
require 'bunny'
|
2
|
-
require 'celluloid/autostart'
|
3
2
|
|
4
3
|
module RabbitWQ
|
5
4
|
class Server
|
6
5
|
|
7
|
-
include
|
6
|
+
include Servitude::Server
|
7
|
+
include Servitude::ServerThreaded
|
8
8
|
include Queues
|
9
|
-
include ServerLogging
|
10
9
|
|
11
|
-
|
12
|
-
|
10
|
+
after_initialize :initialize_work_logger
|
11
|
+
after_initialize :load_environment
|
12
|
+
|
13
|
+
attr_reader :work_consumer,
|
13
14
|
:work_exchange
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
finalize do
|
17
|
+
info 'Shutting down ...'
|
17
18
|
|
18
|
-
|
19
|
+
work_consumer.cancel
|
20
|
+
mq.close
|
19
21
|
end
|
20
22
|
|
21
|
-
|
22
|
-
log_startup
|
23
|
-
run
|
23
|
+
protected
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
def handler_class
|
26
|
+
RabbitWQ::MessageHandler
|
27
27
|
end
|
28
28
|
|
29
|
-
|
29
|
+
def run
|
30
|
+
@work_consumer = work_subscribe_queue.subscribe( manual_ack: true ) do |delivery_info, metadata, payload|
|
31
|
+
with_supervision( delivery_info: delivery_info ) do
|
32
|
+
debug( "#{Rainbow( "LISTENER RECEIVED " ).magenta} #{payload}" )
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
34
|
+
call_handler_respecting_thread_count( payload: payload,
|
35
|
+
delivery_info: delivery_info,
|
36
|
+
metadata: metadata,
|
37
|
+
channel: channel )
|
38
|
+
end
|
39
|
+
end
|
35
40
|
end
|
36
41
|
|
37
42
|
def work_exchange
|
@@ -45,56 +50,38 @@ module RabbitWQ
|
|
45
50
|
bind( work_exchange )
|
46
51
|
end
|
47
52
|
|
48
|
-
def
|
49
|
-
|
53
|
+
def error_queue
|
54
|
+
channel.queue( config.error_queue, durable: true )
|
50
55
|
end
|
51
56
|
|
52
|
-
def
|
53
|
-
|
54
|
-
Celluloid::Actor[:message_handler] = MessageHandler.new
|
55
|
-
end
|
56
|
-
|
57
|
-
@work_consumer = work_subscribe_queue.subscribe( manual_ack: true ) do |delivery_info, metadata, payload|
|
58
|
-
info "LISTENER RECEIVED #{payload}"
|
59
|
-
|
60
|
-
if threads > 1
|
61
|
-
pool.async.call( payload: payload,
|
62
|
-
delivery_info: delivery_info,
|
63
|
-
metadata: metadata,
|
64
|
-
channel: channel )
|
65
|
-
else
|
66
|
-
message_handler.call( payload: payload,
|
67
|
-
delivery_info: delivery_info,
|
68
|
-
metadata: metadata,
|
69
|
-
channel: channel )
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def message_handler
|
75
|
-
Celluloid::Actor[:message_handler]
|
57
|
+
def warn_for_supevision_error
|
58
|
+
warn( Rainbow( "RETRYING due to waiting on supervisor to restart actor ..." ).cyan )
|
76
59
|
end
|
77
60
|
|
78
|
-
def
|
79
|
-
|
61
|
+
def warn_for_dead_actor_error
|
62
|
+
warn( Rainbow( "RETRYING due to Celluloid::DeadActorError ..." ).blue )
|
80
63
|
end
|
81
64
|
|
82
|
-
def
|
83
|
-
|
65
|
+
def log_error( e )
|
66
|
+
parts = [Rainbow( [e.class.name, e.message].join( ': ' ) ).red, format_backtrace( e.backtrace )]
|
67
|
+
error( parts.join( "\n" ))
|
84
68
|
end
|
85
69
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
70
|
+
def handle_error( options, e )
|
71
|
+
delivery_info = options[:delivery_info]
|
72
|
+
log_error( e )
|
73
|
+
#error_queue.publish( payload, headers: { exception_message: e.message,
|
74
|
+
#exception_class: e.class.name,
|
75
|
+
#exception_backtrace: e.backtrace } )
|
76
|
+
debug( Rainbow( "NACK" ).red + " #{e.message}" )
|
77
|
+
channel.nack( delivery_info.delivery_tag )
|
78
|
+
rescue => ex
|
79
|
+
error( Rainbow( "ERROR while handling error | #{ex.class.name} | #{ex.message} | #{ex.backtrace.inspect}" ).red )
|
91
80
|
end
|
92
81
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
Configuration.from_file( options[:config] )
|
97
|
-
end
|
82
|
+
def initialize_work_logger
|
83
|
+
RabbitWQ.work_logger = WorkLogger.new( config.work_log_level,
|
84
|
+
config.work_log_path )
|
98
85
|
end
|
99
86
|
|
100
87
|
def load_environment
|
@@ -107,18 +94,8 @@ module RabbitWQ
|
|
107
94
|
require environment_file_path
|
108
95
|
end
|
109
96
|
|
110
|
-
def resolve_threads
|
111
|
-
if options[:threads]
|
112
|
-
RabbitWQ.configuration.threads = options[:threads]
|
113
|
-
end
|
114
|
-
|
115
|
-
return if RabbitWQ.configuration.threads
|
116
|
-
|
117
|
-
RabbitWQ.configuration.threads = 1
|
118
|
-
end
|
119
|
-
|
120
97
|
def environment_file_path
|
121
|
-
|
98
|
+
config.environment_file_path
|
122
99
|
end
|
123
100
|
|
124
101
|
end
|
data/lib/rabbit_wq/version.rb
CHANGED
data/lib/rabbit_wq/work.rb
CHANGED
@@ -5,6 +5,10 @@ module RabbitWQ
|
|
5
5
|
|
6
6
|
YAML_MIMETYPE = 'application/yaml'
|
7
7
|
|
8
|
+
def self.config
|
9
|
+
Servitude.configuration ||= RabbitWQ::Configuration.load
|
10
|
+
end
|
11
|
+
|
8
12
|
def self.enqueue( worker, options={} )
|
9
13
|
payload = worker.to_yaml
|
10
14
|
enqueue_payload( payload, options )
|
@@ -82,9 +86,5 @@ module RabbitWQ
|
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
85
|
-
def self.config
|
86
|
-
RabbitWQ.configuration
|
87
|
-
end
|
88
|
-
|
89
89
|
end
|
90
90
|
end
|
@@ -32,7 +32,7 @@ module RabbitWQ
|
|
32
32
|
end
|
33
33
|
|
34
34
|
if worker
|
35
|
-
logger.send( level, "[" +
|
35
|
+
logger.send( level, "[" + Rainbow( "#{worker.class.name}:#{worker.object_id}" ).cyan + "] #{message}" )
|
36
36
|
else
|
37
37
|
logger.send( level, message )
|
38
38
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'yell'
|
2
2
|
|
3
3
|
module RabbitWQ
|
4
|
-
module
|
4
|
+
module WorkLogging
|
5
5
|
|
6
6
|
%w(
|
7
7
|
debug
|
@@ -11,13 +11,6 @@ module RabbitWQ
|
|
11
11
|
warn
|
12
12
|
).each do |level|
|
13
13
|
|
14
|
-
define_method level do |*messages|
|
15
|
-
return unless RabbitWQ.logger
|
16
|
-
messages.each do |message|
|
17
|
-
RabbitWQ.logger.send level, message
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
14
|
define_method "worker_#{level}" do |worker, *messages|
|
22
15
|
return unless RabbitWQ.work_logger
|
23
16
|
messages.each do |message|
|
data/lib/rabbit_wq.rb
CHANGED
@@ -1,41 +1,46 @@
|
|
1
|
-
require '
|
1
|
+
require 'rainbow'
|
2
|
+
require 'servitude'
|
2
3
|
require 'rabbit_wq/version'
|
3
4
|
|
4
5
|
module RabbitWQ
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
autoload :
|
12
|
-
autoload :
|
13
|
-
autoload :
|
14
|
-
autoload :
|
15
|
-
autoload :
|
16
|
-
autoload :
|
17
|
-
autoload :
|
18
|
-
autoload :
|
19
|
-
autoload :
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
7
|
+
include Servitude::Base
|
8
|
+
|
9
|
+
autoload :Command, 'rabbit_wq/command'
|
10
|
+
autoload :Cli, 'rabbit_wq/cli'
|
11
|
+
autoload :Configuration, 'rabbit_wq/configuration'
|
12
|
+
autoload :FinalError, 'rabbit_wq/final_error'
|
13
|
+
autoload :InvalidWorkError, 'rabbit_wq/invalid_work_error'
|
14
|
+
autoload :Queues, 'rabbit_wq/queues'
|
15
|
+
autoload :MessageHandler, 'rabbit_wq/message_handler'
|
16
|
+
autoload :Server, 'rabbit_wq/server'
|
17
|
+
autoload :Work, 'rabbit_wq/work'
|
18
|
+
autoload :Worker, 'rabbit_wq/worker'
|
19
|
+
autoload :WorkLogger, 'rabbit_wq/work_logger'
|
20
|
+
autoload :WorkLogging, 'rabbit_wq/work_logging'
|
21
|
+
|
22
|
+
def self.perform_boot
|
23
|
+
author = 'C. Jason Harrelson'
|
24
|
+
|
25
|
+
years = 2013
|
26
|
+
years = "#{years}–#{::Time.now.year}" if years < ::Time.now.year
|
27
|
+
|
28
|
+
boot host_namespace: self,
|
29
|
+
app_name: 'Rabbit WQ',
|
30
|
+
author: author,
|
31
|
+
attribution: "v#{VERSION} Copyright © #{years} #{author}",
|
32
|
+
default_config_path: "/etc/rabbit-wq/#{process_name}.conf",
|
33
|
+
use_config: true
|
26
34
|
end
|
27
35
|
|
28
|
-
def self.
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.configure
|
33
|
-
yield( configuration ) if block_given?
|
36
|
+
def self.process_name
|
37
|
+
'rabbit-wq'
|
34
38
|
end
|
35
39
|
|
36
40
|
class << self
|
37
|
-
attr_accessor :
|
38
|
-
:work_logger
|
41
|
+
attr_accessor :work_logger
|
39
42
|
end
|
40
43
|
|
44
|
+
perform_boot
|
45
|
+
|
41
46
|
end
|
data/rabbit-wq.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_dependency "bunny", "~> 1"
|
25
25
|
spec.add_dependency "celluloid", "~> 0"
|
26
26
|
spec.add_dependency "oj", "~> 2"
|
27
|
-
spec.add_dependency "
|
27
|
+
spec.add_dependency "servitude", ">= 1.2", "< 2"
|
28
28
|
spec.add_dependency "yell", "~> 1"
|
29
29
|
|
30
30
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rabbit-wq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- C. Jason Harrelson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -81,17 +81,23 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '2'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: servitude
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.2'
|
90
|
+
- - "<"
|
88
91
|
- !ruby/object:Gem::Version
|
89
92
|
version: '2'
|
90
93
|
type: :runtime
|
91
94
|
prerelease: false
|
92
95
|
version_requirements: !ruby/object:Gem::Requirement
|
93
96
|
requirements:
|
94
|
-
- - "
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '1.2'
|
100
|
+
- - "<"
|
95
101
|
- !ruby/object:Gem::Version
|
96
102
|
version: '2'
|
97
103
|
- !ruby/object:Gem::Dependency
|
@@ -124,22 +130,20 @@ files:
|
|
124
130
|
- README.md
|
125
131
|
- Rakefile
|
126
132
|
- bin/rabbit-wq
|
127
|
-
- lib/ansi.rb
|
128
133
|
- lib/rabbit-wq.rb
|
129
134
|
- lib/rabbit_wq.rb
|
130
135
|
- lib/rabbit_wq/cli.rb
|
131
136
|
- lib/rabbit_wq/command.rb
|
132
137
|
- lib/rabbit_wq/configuration.rb
|
133
138
|
- lib/rabbit_wq/final_error.rb
|
134
|
-
- lib/rabbit_wq/
|
139
|
+
- lib/rabbit_wq/invalid_work_error.rb
|
135
140
|
- lib/rabbit_wq/message_handler.rb
|
136
141
|
- lib/rabbit_wq/queues.rb
|
137
142
|
- lib/rabbit_wq/server.rb
|
138
|
-
- lib/rabbit_wq/server_daemon.rb
|
139
|
-
- lib/rabbit_wq/server_logging.rb
|
140
143
|
- lib/rabbit_wq/version.rb
|
141
144
|
- lib/rabbit_wq/work.rb
|
142
145
|
- lib/rabbit_wq/work_logger.rb
|
146
|
+
- lib/rabbit_wq/work_logging.rb
|
143
147
|
- lib/rabbit_wq/worker.rb
|
144
148
|
- rabbit-wq.gemspec
|
145
149
|
homepage: ''
|
data/lib/ansi.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
class ANSI
|
2
|
-
|
3
|
-
def self.resolve_text( color, &block )
|
4
|
-
text = nil
|
5
|
-
if block_given?
|
6
|
-
text = block.call + reset
|
7
|
-
end
|
8
|
-
"\e[#{chart[color.to_sym]}m#{text}"
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.reset
|
12
|
-
"\e[0m"
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.chart
|
16
|
-
{
|
17
|
-
black: 30,
|
18
|
-
red: 31,
|
19
|
-
green: 32,
|
20
|
-
yellow: 33,
|
21
|
-
blue: 34,
|
22
|
-
magenta: 35,
|
23
|
-
cyan: 36,
|
24
|
-
white: 37
|
25
|
-
}
|
26
|
-
end
|
27
|
-
|
28
|
-
chart.keys.each do |color|
|
29
|
-
|
30
|
-
define_singleton_method color do |&block|
|
31
|
-
resolve_text color, &block
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
@@ -1,149 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'fileutils'
|
3
|
-
require 'timeout'
|
4
|
-
|
5
|
-
module RabbitWQ
|
6
|
-
class ServerDaemon
|
7
|
-
|
8
|
-
attr_reader :name,
|
9
|
-
:options,
|
10
|
-
:pid,
|
11
|
-
:pid_path,
|
12
|
-
:script,
|
13
|
-
:timeout
|
14
|
-
|
15
|
-
def initialize( options )
|
16
|
-
@options = options
|
17
|
-
@name = options[:name] || APP_NAME
|
18
|
-
@pid_path = options[:pid] || '.'
|
19
|
-
@pid = get_pid
|
20
|
-
@timeout = options[:timeout] || 10
|
21
|
-
end
|
22
|
-
|
23
|
-
def start
|
24
|
-
abort "Process already running!" if process_exists?
|
25
|
-
|
26
|
-
pid = fork do
|
27
|
-
exit if fork
|
28
|
-
Process.setsid
|
29
|
-
exit if fork
|
30
|
-
store_pid( Process.pid )
|
31
|
-
File.umask 0000
|
32
|
-
redirect_output!
|
33
|
-
run
|
34
|
-
end
|
35
|
-
|
36
|
-
Process.waitpid( pid )
|
37
|
-
end
|
38
|
-
|
39
|
-
def run
|
40
|
-
Server.new( options ).start
|
41
|
-
end
|
42
|
-
|
43
|
-
def stop
|
44
|
-
kill_process
|
45
|
-
FileUtils.rm pid_path
|
46
|
-
end
|
47
|
-
|
48
|
-
def status
|
49
|
-
$stdout.print "#{APP_NAME} "
|
50
|
-
if process_exists?
|
51
|
-
$stdout.puts "process running with PID: #{pid}"
|
52
|
-
true
|
53
|
-
else
|
54
|
-
$stdout.puts "process does not exist"
|
55
|
-
false
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
protected
|
60
|
-
|
61
|
-
#def create_pid( pid )
|
62
|
-
def store_pid( pid )
|
63
|
-
File.open( pid_path, 'w' ) do |f|
|
64
|
-
f.puts pid
|
65
|
-
end
|
66
|
-
rescue => e
|
67
|
-
$stderr.puts "Unable to open #{pid_path} for writing:\n\t(#{e.class}) #{e.message}"
|
68
|
-
exit!
|
69
|
-
end
|
70
|
-
|
71
|
-
def get_pid
|
72
|
-
return nil unless File.exists?( pid_path )
|
73
|
-
pid = nil
|
74
|
-
File.open( @pid_path, 'r' ) do |f|
|
75
|
-
pid = f.readline.to_s.gsub( /[^0-9]/, '' )
|
76
|
-
end
|
77
|
-
pid.to_i
|
78
|
-
rescue Errno::ENOENT
|
79
|
-
nil
|
80
|
-
end
|
81
|
-
|
82
|
-
def remove_pidfile
|
83
|
-
File.unlink( pid_path )
|
84
|
-
rescue => e
|
85
|
-
$stderr.puts "Unable to unlink #{pid_path}:\n\t(#{e.class}) #{e.message}"
|
86
|
-
exit
|
87
|
-
end
|
88
|
-
|
89
|
-
def kill_process
|
90
|
-
unless process_exists?
|
91
|
-
$stdout.write "#{APP_NAME} process is not running"
|
92
|
-
return
|
93
|
-
end
|
94
|
-
|
95
|
-
$stdout.write "Attempting to stop #{APP_NAME} process #{pid}..."
|
96
|
-
Process.kill INT, pid
|
97
|
-
iteration_num = 0
|
98
|
-
while process_exists? && iteration_num < 10
|
99
|
-
sleep 1
|
100
|
-
$stdout.write "."
|
101
|
-
iteration_num += 1
|
102
|
-
end
|
103
|
-
if process_exists?
|
104
|
-
$stderr.puts "\nFailed to stop #{APP_NAME} process #{pid}"
|
105
|
-
else
|
106
|
-
$stdout.puts "\nSuccessfuly stopped #{APP_NAME} process #{pid}"
|
107
|
-
end
|
108
|
-
rescue Errno::EPERM
|
109
|
-
$stderr.puts "No permission to query #{pid}!";
|
110
|
-
end
|
111
|
-
|
112
|
-
def process_exists?
|
113
|
-
return false unless pid
|
114
|
-
Process.kill( 0, pid )
|
115
|
-
true
|
116
|
-
rescue Errno::ESRCH, TypeError # "PID is NOT running or is zombied
|
117
|
-
false
|
118
|
-
rescue Errno::EPERM
|
119
|
-
$stderr.puts "No permission to query #{pid}!";
|
120
|
-
false
|
121
|
-
end
|
122
|
-
|
123
|
-
def redirect_output!
|
124
|
-
if log_path = options[:log]
|
125
|
-
#puts "redirecting to log"
|
126
|
-
# if the log directory doesn't exist, create it
|
127
|
-
FileUtils.mkdir_p( File.dirname( log_path ), :mode => 0755 )
|
128
|
-
# touch the log file to create it
|
129
|
-
FileUtils.touch( log_path )
|
130
|
-
# Set permissions on the log file
|
131
|
-
File.chmod( 0644, log_path )
|
132
|
-
# Reopen $stdout (NOT +STDOUT+) to start writing to the log file
|
133
|
-
$stdout.reopen( log_path, 'a' )
|
134
|
-
# Redirect $stderr to $stdout
|
135
|
-
$stderr.reopen $stdout
|
136
|
-
$stdout.sync = true
|
137
|
-
else
|
138
|
-
#puts "redirecting to /dev/null"
|
139
|
-
# We're not bothering to sync if we're dumping to /dev/null
|
140
|
-
# because /dev/null doesn't care about buffered output
|
141
|
-
$stdin.reopen '/dev/null'
|
142
|
-
$stdout.reopen '/dev/null', 'a'
|
143
|
-
$stderr.reopen $stdout
|
144
|
-
end
|
145
|
-
log_path = options[:log] ? options[:log] : '/dev/null'
|
146
|
-
end
|
147
|
-
|
148
|
-
end
|
149
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'yell'
|
2
|
-
|
3
|
-
# Provides logging services for the base server.
|
4
|
-
#
|
5
|
-
module RabbitWQ
|
6
|
-
module ServerLogging
|
7
|
-
|
8
|
-
protected
|
9
|
-
|
10
|
-
def initialize_loggers
|
11
|
-
RabbitWQ.logger = Yell.new do |l|
|
12
|
-
l.level = log_level
|
13
|
-
l.adapter $stdout, :level => [:debug, :info, :warn]
|
14
|
-
l.adapter $stderr, :level => [:error, :fatal]
|
15
|
-
end
|
16
|
-
|
17
|
-
RabbitWQ.work_logger = WorkLogger.new( RabbitWQ.configuration.work_log_level,
|
18
|
-
RabbitWQ.configuration.work_log_path )
|
19
|
-
#Celluloid.logger = Yell.new do |l|
|
20
|
-
#l.level = :info
|
21
|
-
#l.adapter :file, File.join( File.dirname( options[:log] ), "#{APP_ID}-celluloid.log" )
|
22
|
-
#end
|
23
|
-
end
|
24
|
-
|
25
|
-
def log_startup
|
26
|
-
start_banner( options ).each do |line|
|
27
|
-
RabbitWQ.logger.info line
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def start_banner( options )
|
32
|
-
[
|
33
|
-
"",
|
34
|
-
"***",
|
35
|
-
"* #{APP_NAME} started",
|
36
|
-
"*",
|
37
|
-
"* #{VERSION_COPYRIGHT}",
|
38
|
-
"*",
|
39
|
-
"* Configuration:",
|
40
|
-
(options[:config_loaded] ? "* file: #{options[:config]}" : nil),
|
41
|
-
RabbitWQ::Configuration.attributes.map { |a| "* #{a}: #{RabbitWQ.configuration.send( a )}" },
|
42
|
-
"*",
|
43
|
-
"***",
|
44
|
-
].flatten.reject( &:nil? )
|
45
|
-
end
|
46
|
-
|
47
|
-
def log_level
|
48
|
-
options.fetch( :log_level, :info ).to_sym
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|