eventq_rabbitmq 1.17.0-java
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 +7 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/eventq_rabbitmq/default_queue.rb +12 -0
- data/lib/eventq_rabbitmq/jruby/rabbitmq_queue_worker.rb +373 -0
- data/lib/eventq_rabbitmq/rabbitmq_eventq_client.rb +127 -0
- data/lib/eventq_rabbitmq/rabbitmq_queue_client.rb +54 -0
- data/lib/eventq_rabbitmq/rabbitmq_queue_manager.rb +104 -0
- data/lib/eventq_rabbitmq/rabbitmq_queue_worker.rb +389 -0
- data/lib/eventq_rabbitmq/rabbitmq_status_checker.rb +62 -0
- data/lib/eventq_rabbitmq/rabbitmq_subscription_manager.rb +54 -0
- data/lib/eventq_rabbitmq/version.rb +3 -0
- data/lib/eventq_rabbitmq.rb +49 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2ac92d8a90294367f4ee7b8f69034b90f6605d8481d755c8a50712a272acb103
|
4
|
+
data.tar.gz: 4fc200d78f706bf3fd57040a4b310b6b7a591ba3337a2114582d2aea814c4a8d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cdc0d278a62aea36ece0309710cc34ee46b7d3229f0d819b15bec7e23b65e128d60ff14d90c11e969b2a5d437771dd3a8608b8d51bd581d23a34502390642cb0
|
7
|
+
data.tar.gz: 2710024884afd8230a1762cde151983321b37fe67dfa4c19d450466d72fd3029f24a268ef741fa75daba3364fc8885125d41f3ec7c1d4c691db707f37d6a4892
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "eventq_rabbitmq"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,373 @@
|
|
1
|
+
require 'java'
|
2
|
+
java_import java.util.concurrent.Executors
|
3
|
+
module EventQ
|
4
|
+
module RabbitMq
|
5
|
+
class QueueWorker
|
6
|
+
include EventQ::WorkerId
|
7
|
+
|
8
|
+
attr_accessor :is_running
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@threads = []
|
12
|
+
@forks = []
|
13
|
+
@is_running = false
|
14
|
+
|
15
|
+
@retry_exceeded_block = nil
|
16
|
+
@on_retry_block = nil
|
17
|
+
@on_error_block = nil
|
18
|
+
@hash_helper = HashKit::Helper.new
|
19
|
+
@serialization_provider_manager = EventQ::SerializationProviders::Manager.new
|
20
|
+
@signature_provider_manager = EventQ::SignatureProviders::Manager.new
|
21
|
+
@last_gc_flush = Time.now
|
22
|
+
@gc_flush_interval = 10
|
23
|
+
end
|
24
|
+
|
25
|
+
def start(queue, options = {}, &block)
|
26
|
+
|
27
|
+
EventQ.logger.info("[#{self.class}] - Preparing to start listening for messages.")
|
28
|
+
|
29
|
+
configure(queue, options)
|
30
|
+
|
31
|
+
raise "[#{self.class}] - Worker is already running." if running?
|
32
|
+
|
33
|
+
if options[:client] == nil
|
34
|
+
raise "[#{self.class}] - :client (QueueClient) must be specified."
|
35
|
+
end
|
36
|
+
|
37
|
+
EventQ.logger.info("[#{self.class}] - Listening for messages.")
|
38
|
+
EventQ.logger.debug do
|
39
|
+
"[#{self.class} #start] - Listening for messages on queue: #{EventQ.create_queue_name(queue.name)}"
|
40
|
+
end
|
41
|
+
|
42
|
+
start_process(options, queue, block)
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def start_process(options, queue, block)
|
47
|
+
|
48
|
+
@is_running = true
|
49
|
+
|
50
|
+
%w'INT TERM'.each do |sig|
|
51
|
+
Signal.trap(sig) {
|
52
|
+
stop
|
53
|
+
exit
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
if !options.key?(:durable)
|
58
|
+
options[:durable] = true
|
59
|
+
end
|
60
|
+
|
61
|
+
client = options[:client]
|
62
|
+
manager = EventQ::RabbitMq::QueueManager.new
|
63
|
+
manager.durable = options[:durable]
|
64
|
+
@connection = client.get_connection
|
65
|
+
|
66
|
+
@executor = java.util.concurrent.Executors::newFixedThreadPool @thread_count
|
67
|
+
|
68
|
+
#loop through each thread count
|
69
|
+
@thread_count.times do
|
70
|
+
|
71
|
+
@executor.execute do
|
72
|
+
|
73
|
+
#begin the queue loop for this thread
|
74
|
+
while true do
|
75
|
+
|
76
|
+
#check if the worker is still allowed to run and break out of thread loop if not
|
77
|
+
unless running?
|
78
|
+
break
|
79
|
+
end
|
80
|
+
|
81
|
+
if @executor.is_shutdown
|
82
|
+
break
|
83
|
+
end
|
84
|
+
|
85
|
+
has_received_message = false
|
86
|
+
|
87
|
+
begin
|
88
|
+
|
89
|
+
channel = @connection.create_channel
|
90
|
+
|
91
|
+
has_received_message = thread_process_iteration(channel, manager, queue, block)
|
92
|
+
|
93
|
+
rescue => e
|
94
|
+
EventQ.logger.error("An unhandled error occurred. Error: #{e} | Backtrace: #{e.backtrace}")
|
95
|
+
call_on_error_block(error: e)
|
96
|
+
end
|
97
|
+
|
98
|
+
if channel != nil && channel.open?
|
99
|
+
channel.close
|
100
|
+
end
|
101
|
+
|
102
|
+
gc_flush
|
103
|
+
|
104
|
+
if !has_received_message
|
105
|
+
EventQ.logger.debug { "[#{self.class}] - No message received." }
|
106
|
+
if @sleep > 0
|
107
|
+
EventQ.logger.debug { "[#{self.class}] - Sleeping for #{@sleep} seconds" }
|
108
|
+
sleep(@sleep)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
if options.key?(:wait) && options[:wait] == true
|
119
|
+
while running? do end
|
120
|
+
@connection.close if @connection.open?
|
121
|
+
end
|
122
|
+
|
123
|
+
return true
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
def call_on_error_block(error:, message: nil)
|
128
|
+
if @on_error_block
|
129
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_error block." }
|
130
|
+
begin
|
131
|
+
@on_error_block.call(error, message)
|
132
|
+
rescue => e
|
133
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_error block. Error: #{e}")
|
134
|
+
end
|
135
|
+
else
|
136
|
+
EventQ.logger.debug { "[#{self.class}] - No on_error block specified to execute." }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def gc_flush
|
141
|
+
if Time.now - last_gc_flush > @gc_flush_interval
|
142
|
+
GC.start
|
143
|
+
@last_gc_flush = Time.now
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def last_gc_flush
|
148
|
+
@last_gc_flush
|
149
|
+
end
|
150
|
+
|
151
|
+
def thread_process_iteration(channel, manager, queue, block)
|
152
|
+
|
153
|
+
#get the queue
|
154
|
+
q = manager.get_queue(channel, queue)
|
155
|
+
retry_exchange = manager.get_retry_exchange(channel, queue)
|
156
|
+
|
157
|
+
received = false
|
158
|
+
|
159
|
+
begin
|
160
|
+
delivery_info, payload = manager.pop_message(queue: q)
|
161
|
+
|
162
|
+
#check that message was received
|
163
|
+
if payload != nil
|
164
|
+
received = true
|
165
|
+
begin
|
166
|
+
tag_processing_thread
|
167
|
+
process_message(payload, queue, channel, retry_exchange, delivery_info, block)
|
168
|
+
ensure
|
169
|
+
untag_processing_thread
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
rescue => e
|
175
|
+
EventQ.logger.error("[#{self.class}] - An error occurred attempting to process a message. Error: #{e} | Backtrace: #{e.backtrace}")
|
176
|
+
call_on_error_block(error: e)
|
177
|
+
end
|
178
|
+
|
179
|
+
return received
|
180
|
+
end
|
181
|
+
|
182
|
+
def stop
|
183
|
+
EventQ.logger.info { "[#{self.class}] - Stopping..." }
|
184
|
+
@is_running = false
|
185
|
+
@executor.shutdown
|
186
|
+
if @connection != nil
|
187
|
+
@connection.close if @connection.open?
|
188
|
+
end
|
189
|
+
return true
|
190
|
+
end
|
191
|
+
|
192
|
+
def on_retry_exceeded(&block)
|
193
|
+
@retry_exceeded_block = block
|
194
|
+
return nil
|
195
|
+
end
|
196
|
+
|
197
|
+
def on_retry(&block)
|
198
|
+
@on_retry_block = block
|
199
|
+
return nil
|
200
|
+
end
|
201
|
+
|
202
|
+
def on_error(&block)
|
203
|
+
@on_error_block = block
|
204
|
+
return nil
|
205
|
+
end
|
206
|
+
|
207
|
+
def running?
|
208
|
+
return @is_running
|
209
|
+
end
|
210
|
+
|
211
|
+
def deserialize_message(payload)
|
212
|
+
provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
|
213
|
+
return provider.deserialize(payload)
|
214
|
+
end
|
215
|
+
|
216
|
+
def serialize_message(msg)
|
217
|
+
provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
|
218
|
+
return provider.serialize(msg)
|
219
|
+
end
|
220
|
+
|
221
|
+
def call_on_retry_exceeded_block(message)
|
222
|
+
if @retry_exceeded_block != nil
|
223
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_retry_exceeded block." }
|
224
|
+
begin
|
225
|
+
@retry_exceeded_block.call(message)
|
226
|
+
rescue => e
|
227
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry_exceeded block. Error: #{e}")
|
228
|
+
end
|
229
|
+
else
|
230
|
+
EventQ.logger.debug { "[#{self.class}] - No on_retry_exceeded block specified." }
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def call_on_retry_block(message)
|
235
|
+
if @on_retry_block
|
236
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_retry block." }
|
237
|
+
begin
|
238
|
+
@on_retry_block.call(message, abort)
|
239
|
+
rescue => e
|
240
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry block. Error: #{e}")
|
241
|
+
end
|
242
|
+
else
|
243
|
+
EventQ.logger.debug { "[#{self.class}] - No on_retry block specified." }
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def reject_message(channel, message, delivery_tag, retry_exchange, queue, abort)
|
248
|
+
|
249
|
+
EventQ.logger.info("[#{self.class}] - Message rejected removing from queue.")
|
250
|
+
#reject the message to remove from queue
|
251
|
+
channel.reject(delivery_tag, false)
|
252
|
+
|
253
|
+
#check if the message retry limit has been exceeded
|
254
|
+
if message.retry_attempts >= queue.max_retry_attempts
|
255
|
+
|
256
|
+
EventQ.logger.info("[#{self.class}] - Message retry attempt limit exceeded. Msg: #{serialize_message(message)}")
|
257
|
+
|
258
|
+
call_on_retry_exceeded_block(message)
|
259
|
+
|
260
|
+
#check if the message is allowed to be retried
|
261
|
+
elsif queue.allow_retry
|
262
|
+
|
263
|
+
EventQ.logger.debug { "[#{self.class}] - Incrementing retry attempts count." }
|
264
|
+
message.retry_attempts += 1
|
265
|
+
|
266
|
+
if queue.allow_retry_back_off == true
|
267
|
+
EventQ.logger.debug { "[#{self.class}] - Calculating message back off retry delay. Attempts: #{message.retry_attempts} * Retry Delay: #{queue.retry_delay}" }
|
268
|
+
message_ttl = message.retry_attempts * queue.retry_delay
|
269
|
+
if (message.retry_attempts * queue.retry_delay) > queue.max_retry_delay
|
270
|
+
EventQ.logger.debug { "[#{self.class}] - Max message back off retry delay reached." }
|
271
|
+
message_ttl = queue.max_retry_delay
|
272
|
+
end
|
273
|
+
else
|
274
|
+
EventQ.logger.debug { "[#{self.class}] - Setting fixed retry delay for message." }
|
275
|
+
message_ttl = queue.retry_delay
|
276
|
+
end
|
277
|
+
|
278
|
+
EventQ.logger.debug { "[#{self.class}] - Sending message for retry. Message TTL: #{message_ttl}" }
|
279
|
+
retry_exchange.publish(serialize_message(message), :expiration => message_ttl)
|
280
|
+
EventQ.logger.debug { "[#{self.class}] - Published message to retry exchange." }
|
281
|
+
|
282
|
+
call_on_retry_block(message)
|
283
|
+
|
284
|
+
end
|
285
|
+
|
286
|
+
return true
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
def configure(queue, options = {})
|
291
|
+
|
292
|
+
@queue = queue
|
293
|
+
|
294
|
+
#default thread count
|
295
|
+
@thread_count = 4
|
296
|
+
if options.key?(:thread_count)
|
297
|
+
@thread_count = options[:thread_count]
|
298
|
+
end
|
299
|
+
|
300
|
+
#default sleep time in seconds
|
301
|
+
@sleep = 15
|
302
|
+
if options.key?(:sleep)
|
303
|
+
@sleep = options[:sleep]
|
304
|
+
end
|
305
|
+
|
306
|
+
@fork_count = 1
|
307
|
+
if options.key?(:fork_count)
|
308
|
+
@fork_count = options[:fork_count]
|
309
|
+
end
|
310
|
+
|
311
|
+
@gc_flush_interval = 10
|
312
|
+
if options.key?(:gc_flush_interval)
|
313
|
+
@gc_flush_interval = options[:gc_flush_interval]
|
314
|
+
end
|
315
|
+
|
316
|
+
EventQ.logger.info("[#{self.class}] - Configuring. Process Count: #{@fork_count} | Thread Count: #{@thread_count} | Interval Sleep: #{@sleep}.")
|
317
|
+
|
318
|
+
return true
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
private
|
323
|
+
|
324
|
+
def process_message(payload, queue, channel, retry_exchange, delivery_tag, block)
|
325
|
+
abort = false
|
326
|
+
error = false
|
327
|
+
message = deserialize_message(payload)
|
328
|
+
|
329
|
+
EventQ.logger.info("[#{self.class}] - Message received. Retry Attempts: #{message.retry_attempts}")
|
330
|
+
|
331
|
+
@signature_provider_manager.validate_signature(message: message, queue: queue)
|
332
|
+
|
333
|
+
message_args = EventQ::MessageArgs.new(type: message.type,
|
334
|
+
retry_attempts: message.retry_attempts,
|
335
|
+
context: message.context,
|
336
|
+
content_type: message.content_type)
|
337
|
+
|
338
|
+
if(!EventQ::NonceManager.is_allowed?(message.id))
|
339
|
+
EventQ.logger.info("[#{self.class}] - Duplicate Message received. Dropping message.")
|
340
|
+
channel.acknowledge(delivery_tag, false)
|
341
|
+
return false
|
342
|
+
end
|
343
|
+
|
344
|
+
#begin worker block for queue message
|
345
|
+
begin
|
346
|
+
block.call(message.content, message_args)
|
347
|
+
|
348
|
+
if message_args.abort == true
|
349
|
+
abort = true
|
350
|
+
EventQ.logger.info("[#{self.class}] - Message aborted.")
|
351
|
+
else
|
352
|
+
#accept the message as processed
|
353
|
+
channel.acknowledge(delivery_tag, false)
|
354
|
+
EventQ.logger.info("[#{self.class}] - Message acknowledged.")
|
355
|
+
end
|
356
|
+
|
357
|
+
rescue => e
|
358
|
+
EventQ.logger.error("[#{self.class}] - An unhandled error happened attempting to process a queue message. Error: #{e} | Backtrace: #{e.backtrace}")
|
359
|
+
error = true
|
360
|
+
call_on_error_block(error: e, message: message)
|
361
|
+
end
|
362
|
+
|
363
|
+
if error || abort
|
364
|
+
EventQ::NonceManager.failed(message.id)
|
365
|
+
reject_message(channel, message, delivery_tag, retry_exchange, queue, abort)
|
366
|
+
else
|
367
|
+
EventQ::NonceManager.complete(message.id)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module EventQ
|
2
|
+
module RabbitMq
|
3
|
+
# Implements a general interface to raise an event
|
4
|
+
# EventQ::Amazon::EventQClient is the sister-class which does the same for AWS
|
5
|
+
class EventQClient
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
|
9
|
+
if options[:client] == nil
|
10
|
+
raise ':client (QueueClient) must be specified.'.freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
@client = options[:client]
|
14
|
+
@queue_manager = QueueManager.new
|
15
|
+
@event_raised_exchange = EventRaisedExchange.new
|
16
|
+
@serialization_manager = EventQ::SerializationProviders::Manager.new
|
17
|
+
@signature_manager = EventQ::SignatureProviders::Manager.new
|
18
|
+
|
19
|
+
#this array is used to record known event types
|
20
|
+
@known_event_types = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def registered?(event_type)
|
24
|
+
@known_event_types.include?(event_type)
|
25
|
+
end
|
26
|
+
|
27
|
+
def register_event(event_type)
|
28
|
+
if registered?(event_type)
|
29
|
+
return true
|
30
|
+
end
|
31
|
+
|
32
|
+
@known_event_types << event_type
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def publish(topic:, event:, context: {})
|
37
|
+
raise_event(topic, event, context)
|
38
|
+
end
|
39
|
+
|
40
|
+
def raise_event(event_type, event, context = {})
|
41
|
+
register_event(event_type)
|
42
|
+
|
43
|
+
_event_type = EventQ.create_event_type(event_type)
|
44
|
+
|
45
|
+
with_connection do |channel|
|
46
|
+
exchange = @queue_manager.get_exchange(channel, @event_raised_exchange)
|
47
|
+
|
48
|
+
message = serialized_message(_event_type, event, context)
|
49
|
+
|
50
|
+
exchange.publish(message, routing_key: _event_type)
|
51
|
+
|
52
|
+
EventQ.logger.debug do
|
53
|
+
"[#{self.class}] - Raised event to Exchange: #{_event_type} | Message: #{message}."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def raise_event_in_queue(event_type, event, queue, delay, context = {})
|
59
|
+
register_event(event_type)
|
60
|
+
|
61
|
+
_event_type = EventQ.create_event_type(event_type)
|
62
|
+
|
63
|
+
with_connection do |channel|
|
64
|
+
exchange = @queue_manager.get_queue_exchange(channel, queue)
|
65
|
+
|
66
|
+
delay_exchange = @queue_manager.get_delay_exchange(channel, queue, delay)
|
67
|
+
|
68
|
+
delay_queue = @queue_manager.create_delay_queue(channel, queue, exchange.name, delay)
|
69
|
+
delay_queue.bind(delay_exchange, routing_key: _event_type)
|
70
|
+
|
71
|
+
_queue_name = EventQ.create_queue_name(queue.name)
|
72
|
+
|
73
|
+
q = channel.queue(_queue_name, durable: @queue_manager.durable)
|
74
|
+
q.bind(exchange, routing_key: _event_type)
|
75
|
+
|
76
|
+
message = serialized_message(_event_type, event, context)
|
77
|
+
|
78
|
+
delay_exchange.publish(message, routing_key: _event_type)
|
79
|
+
|
80
|
+
EventQ.logger.debug do
|
81
|
+
"[#{self.class}] - Raised event to Exchange: #{_event_type} | Message: #{message} | Delay: #{delay}."
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def new_message
|
87
|
+
EventQ::QueueMessage.new
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def with_connection
|
93
|
+
connection = @client.get_connection
|
94
|
+
|
95
|
+
begin
|
96
|
+
channel = connection.create_channel
|
97
|
+
|
98
|
+
yield(channel)
|
99
|
+
|
100
|
+
ensure
|
101
|
+
channel&.close if channel.open?
|
102
|
+
connection.close
|
103
|
+
end
|
104
|
+
|
105
|
+
true
|
106
|
+
end
|
107
|
+
|
108
|
+
def serialized_message(event_type, event, context)
|
109
|
+
qm = new_message
|
110
|
+
qm.content = event
|
111
|
+
qm.type = event_type
|
112
|
+
qm.context = context
|
113
|
+
qm.content_type = event.class.to_s
|
114
|
+
|
115
|
+
if EventQ::Configuration.signature_secret != nil
|
116
|
+
provider = @signature_manager.get_provider(EventQ::Configuration.signature_provider)
|
117
|
+
qm.signature = provider.write(message: qm, secret: EventQ::Configuration.signature_secret)
|
118
|
+
end
|
119
|
+
|
120
|
+
serialization_provider = @serialization_manager.get_provider(EventQ::Configuration.serialization_provider)
|
121
|
+
|
122
|
+
serialization_provider.serialize(qm)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module EventQ
|
2
|
+
module RabbitMq
|
3
|
+
class QueueClient
|
4
|
+
|
5
|
+
GUEST = 'guest'.freeze
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
|
9
|
+
if options[:endpoint] == nil
|
10
|
+
raise ':endpoint must be specified.'.freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
@endpoint = options[:endpoint]
|
14
|
+
|
15
|
+
@port = Integer(options[:port] || 5672)
|
16
|
+
|
17
|
+
@user = options[:user] || GUEST
|
18
|
+
|
19
|
+
@password = options[:password] || GUEST
|
20
|
+
|
21
|
+
@ssl = options[:ssl] == true || false
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def connection_options
|
26
|
+
{
|
27
|
+
:host => @endpoint,
|
28
|
+
:port => @port,
|
29
|
+
:user => @user,
|
30
|
+
:pass => @password,
|
31
|
+
:ssl => @ssl,
|
32
|
+
:read_timeout => 4,
|
33
|
+
:heartbeat => 8,
|
34
|
+
:continuation_timeout => 5000,
|
35
|
+
:automatically_recover => true,
|
36
|
+
:network_recovery_interval => 1,
|
37
|
+
:recover_from_connection_close => true
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_connection
|
42
|
+
if RUBY_PLATFORM =~ /java/
|
43
|
+
conn = MarchHare.connect(connection_options)
|
44
|
+
else
|
45
|
+
conn = Bunny.new(connection_options)
|
46
|
+
end
|
47
|
+
|
48
|
+
conn.start
|
49
|
+
return conn
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module EventQ
|
2
|
+
module RabbitMq
|
3
|
+
class QueueManager
|
4
|
+
|
5
|
+
X_DEAD_LETTER_EXCHANGE = 'x-dead-letter-exchange'.freeze
|
6
|
+
X_MESSAGE_TTL = 'x-message-ttl'.freeze
|
7
|
+
|
8
|
+
attr_accessor :durable
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@event_raised_exchange = EventQ::EventRaisedExchange.new
|
12
|
+
@durable = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_queue(channel, queue)
|
16
|
+
|
17
|
+
_queue_name = EventQ.create_queue_name(queue.name)
|
18
|
+
|
19
|
+
#get/create the queue
|
20
|
+
q = channel.queue(_queue_name, :durable => @durable)
|
21
|
+
|
22
|
+
if queue.allow_retry
|
23
|
+
retry_exchange = get_retry_exchange(channel, queue)
|
24
|
+
subscriber_exchange = get_subscriber_exchange(channel, queue)
|
25
|
+
|
26
|
+
retry_queue = get_retry_queue(channel, queue)
|
27
|
+
retry_queue.bind(retry_exchange)
|
28
|
+
|
29
|
+
q.bind(subscriber_exchange)
|
30
|
+
end
|
31
|
+
|
32
|
+
return q
|
33
|
+
end
|
34
|
+
|
35
|
+
def pop_message(queue:)
|
36
|
+
if RUBY_PLATFORM =~ /java/
|
37
|
+
headers, payload = queue.pop({ :ack => true, :block => true })
|
38
|
+
if headers == nil
|
39
|
+
return [nil,nil]
|
40
|
+
end
|
41
|
+
[headers.delivery_tag, payload]
|
42
|
+
else
|
43
|
+
headers, properties, payload = queue.pop({ :manual_ack => true, :block => true })
|
44
|
+
if headers == nil
|
45
|
+
return [nil,nil]
|
46
|
+
end
|
47
|
+
[headers.delivery_tag, payload]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_queue_exchange(channel, queue)
|
52
|
+
_exchange_name = EventQ.create_exchange_name(queue.name)
|
53
|
+
channel.direct("#{_exchange_name}.ex")
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_retry_exchange(channel, queue)
|
57
|
+
_queue_name = EventQ.create_queue_name(queue.name)
|
58
|
+
return channel.fanout("#{_queue_name}.r.ex")
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_subscriber_exchange(channel, queue)
|
62
|
+
_queue_name = EventQ.create_queue_name(queue.name)
|
63
|
+
return channel.fanout("#{_queue_name}.ex")
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_delay_exchange(channel, queue, delay)
|
67
|
+
_queue_name = EventQ.create_queue_name(queue.name)
|
68
|
+
channel.direct("#{_queue_name}.#{delay}.d.ex")
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_retry_queue(channel, queue)
|
72
|
+
subscriber_exchange = get_subscriber_exchange(channel, queue)
|
73
|
+
|
74
|
+
_queue_name = EventQ.create_queue_name(queue.name)
|
75
|
+
|
76
|
+
if queue.allow_retry_back_off == true
|
77
|
+
|
78
|
+
EventQ.logger.debug { "[#{self.class}] - Requesting retry queue. x-dead-letter-exchange: #{subscriber_exchange.name} | x-message-ttl: #{queue.max_retry_delay}" }
|
79
|
+
|
80
|
+
return channel.queue("#{_queue_name}.r", :durable => @durable, :arguments => { X_DEAD_LETTER_EXCHANGE => subscriber_exchange.name, X_MESSAGE_TTL => queue.max_retry_delay })
|
81
|
+
|
82
|
+
else
|
83
|
+
|
84
|
+
EventQ.logger.debug { "[#{self.class}] - Requesting retry queue. x-dead-letter-exchange: #{subscriber_exchange.name} | x-message-ttl: #{queue.retry_delay}" }
|
85
|
+
|
86
|
+
return channel.queue("#{_queue_name}.r", :durable => @durable, :arguments => { X_DEAD_LETTER_EXCHANGE => subscriber_exchange.name, X_MESSAGE_TTL => queue.retry_delay })
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
def create_delay_queue(channel, queue, dlx_name, delay=0)
|
93
|
+
queue_name = EventQ.create_queue_name(queue.name)
|
94
|
+
channel.queue("#{queue_name}.#{delay}.delay", durable: @durable,
|
95
|
+
arguments: { X_DEAD_LETTER_EXCHANGE => dlx_name, X_MESSAGE_TTL => delay * 1000 })
|
96
|
+
end
|
97
|
+
|
98
|
+
def get_exchange(channel, exchange)
|
99
|
+
_exchange_name = EventQ.create_exchange_name(exchange.name)
|
100
|
+
return channel.direct(_exchange_name, :durable => @durable)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,389 @@
|
|
1
|
+
module EventQ
|
2
|
+
module RabbitMq
|
3
|
+
class QueueWorker
|
4
|
+
include EventQ::WorkerId
|
5
|
+
|
6
|
+
attr_accessor :is_running
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@threads = []
|
10
|
+
@forks = []
|
11
|
+
@is_running = false
|
12
|
+
|
13
|
+
@retry_exceeded_block = nil
|
14
|
+
@on_retry_block = nil
|
15
|
+
@on_error_block = nil
|
16
|
+
@hash_helper = HashKit::Helper.new
|
17
|
+
@serialization_provider_manager = EventQ::SerializationProviders::Manager.new
|
18
|
+
@signature_provider_manager = EventQ::SignatureProviders::Manager.new
|
19
|
+
@last_gc_flush = Time.now
|
20
|
+
@gc_flush_interval = 10
|
21
|
+
end
|
22
|
+
|
23
|
+
def start(queue, options = {}, &block)
|
24
|
+
|
25
|
+
EventQ.logger.info("[#{self.class}] - Preparing to start listening for messages.")
|
26
|
+
|
27
|
+
configure(queue, options)
|
28
|
+
|
29
|
+
raise "[#{self.class}] - Worker is already running." if running?
|
30
|
+
|
31
|
+
if options[:client] == nil
|
32
|
+
raise "[#{self.class}] - :client (QueueClient) must be specified."
|
33
|
+
end
|
34
|
+
|
35
|
+
EventQ.logger.info("[#{self.class}] - Listening for messages.")
|
36
|
+
EventQ.logger.debug do
|
37
|
+
"[#{self.class} #start] - Listening for messages on queue: #{EventQ.create_queue_name(queue.name)}"
|
38
|
+
end
|
39
|
+
|
40
|
+
@forks = []
|
41
|
+
|
42
|
+
if @fork_count > 1
|
43
|
+
@fork_count.times do
|
44
|
+
pid = fork do
|
45
|
+
start_process(options, queue, block)
|
46
|
+
end
|
47
|
+
@forks.push(pid)
|
48
|
+
end
|
49
|
+
|
50
|
+
if options.key?(:wait) && options[:wait] == true
|
51
|
+
@forks.each { |pid| Process.wait(pid) }
|
52
|
+
end
|
53
|
+
|
54
|
+
else
|
55
|
+
start_process(options, queue, block)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def start_process(options, queue, block)
|
61
|
+
|
62
|
+
@is_running = true
|
63
|
+
|
64
|
+
%w'INT TERM'.each do |sig|
|
65
|
+
Signal.trap(sig) {
|
66
|
+
stop
|
67
|
+
exit
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
if !options.key?(:durable)
|
72
|
+
options[:durable] = true
|
73
|
+
end
|
74
|
+
|
75
|
+
client = options[:client]
|
76
|
+
manager = EventQ::RabbitMq::QueueManager.new
|
77
|
+
manager.durable = options[:durable]
|
78
|
+
@connection = client.get_connection
|
79
|
+
|
80
|
+
@threads = []
|
81
|
+
|
82
|
+
#loop through each thread count
|
83
|
+
@thread_count.times do
|
84
|
+
thr = Thread.new do
|
85
|
+
|
86
|
+
#begin the queue loop for this thread
|
87
|
+
while true do
|
88
|
+
|
89
|
+
#check if the worker is still allowed to run and break out of thread loop if not
|
90
|
+
unless running?
|
91
|
+
break
|
92
|
+
end
|
93
|
+
|
94
|
+
has_received_message = false
|
95
|
+
|
96
|
+
begin
|
97
|
+
|
98
|
+
channel = @connection.create_channel
|
99
|
+
|
100
|
+
has_received_message = thread_process_iteration(channel, manager, queue, block)
|
101
|
+
|
102
|
+
rescue => e
|
103
|
+
EventQ.logger.error("An unhandled error occurred. Error: #{e} | Backtrace: #{e.backtrace}")
|
104
|
+
call_on_error_block(error: e)
|
105
|
+
end
|
106
|
+
|
107
|
+
if channel != nil && channel.open?
|
108
|
+
channel.close
|
109
|
+
end
|
110
|
+
|
111
|
+
gc_flush
|
112
|
+
|
113
|
+
if !has_received_message
|
114
|
+
EventQ.logger.debug { "[#{self.class}] - No message received." }
|
115
|
+
if @sleep > 0
|
116
|
+
EventQ.logger.debug { "[#{self.class}] - Sleeping for #{@sleep} seconds" }
|
117
|
+
sleep(@sleep)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
@threads.push(thr)
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
if options.key?(:wait) && options[:wait] == true
|
129
|
+
@threads.each { |thr| thr.join }
|
130
|
+
@connection.close if @connection.open?
|
131
|
+
end
|
132
|
+
|
133
|
+
return true
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
def call_on_error_block(error:, message: nil)
|
138
|
+
if @on_error_block
|
139
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_error block." }
|
140
|
+
begin
|
141
|
+
@on_error_block.call(error, message)
|
142
|
+
rescue => e
|
143
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_error block. Error: #{e}")
|
144
|
+
end
|
145
|
+
else
|
146
|
+
EventQ.logger.debug { "[#{self.class}] - No on_error block specified to execute." }
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def gc_flush
|
151
|
+
if Time.now - last_gc_flush > @gc_flush_interval
|
152
|
+
GC.start
|
153
|
+
@last_gc_flush = Time.now
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def last_gc_flush
|
158
|
+
@last_gc_flush
|
159
|
+
end
|
160
|
+
|
161
|
+
def thread_process_iteration(channel, manager, queue, block)
|
162
|
+
|
163
|
+
#get the queue
|
164
|
+
q = manager.get_queue(channel, queue)
|
165
|
+
retry_exchange = manager.get_retry_exchange(channel, queue)
|
166
|
+
|
167
|
+
received = false
|
168
|
+
|
169
|
+
begin
|
170
|
+
delivery_info, payload = manager.pop_message(queue: q)
|
171
|
+
|
172
|
+
#check that message was received
|
173
|
+
if payload != nil
|
174
|
+
received = true
|
175
|
+
begin
|
176
|
+
tag_processing_thread
|
177
|
+
process_message(payload, queue, channel, retry_exchange, delivery_info, block)
|
178
|
+
ensure
|
179
|
+
untag_processing_thread
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
rescue => e
|
185
|
+
EventQ.logger.error("[#{self.class}] - An error occurred attempting to process a message. Error: #{e} | Backtrace: #{e.backtrace}")
|
186
|
+
call_on_error_block(error: e)
|
187
|
+
end
|
188
|
+
|
189
|
+
return received
|
190
|
+
end
|
191
|
+
|
192
|
+
def stop
|
193
|
+
EventQ.logger.info { "[#{self.class}] - Stopping..." }
|
194
|
+
@is_running = false
|
195
|
+
Thread.list.each do |thread|
|
196
|
+
thread.exit unless thread == Thread.current
|
197
|
+
end
|
198
|
+
if @connection != nil
|
199
|
+
begin
|
200
|
+
@connection.close if @connection.open?
|
201
|
+
rescue Timeout::Error
|
202
|
+
EventQ.logger.error { 'Timeout occurred closing connection.' }
|
203
|
+
end
|
204
|
+
end
|
205
|
+
return true
|
206
|
+
end
|
207
|
+
|
208
|
+
def on_retry_exceeded(&block)
|
209
|
+
@retry_exceeded_block = block
|
210
|
+
return nil
|
211
|
+
end
|
212
|
+
|
213
|
+
def on_retry(&block)
|
214
|
+
@on_retry_block = block
|
215
|
+
return nil
|
216
|
+
end
|
217
|
+
|
218
|
+
def on_error(&block)
|
219
|
+
@on_error_block = block
|
220
|
+
return nil
|
221
|
+
end
|
222
|
+
|
223
|
+
def running?
|
224
|
+
return @is_running
|
225
|
+
end
|
226
|
+
|
227
|
+
def deserialize_message(payload)
|
228
|
+
provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
|
229
|
+
return provider.deserialize(payload)
|
230
|
+
end
|
231
|
+
|
232
|
+
def serialize_message(msg)
|
233
|
+
provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
|
234
|
+
return provider.serialize(msg)
|
235
|
+
end
|
236
|
+
|
237
|
+
def call_on_retry_exceeded_block(message)
|
238
|
+
if @retry_exceeded_block != nil
|
239
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_retry_exceeded block." }
|
240
|
+
begin
|
241
|
+
@retry_exceeded_block.call(message)
|
242
|
+
rescue => e
|
243
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry_exceeded block. Error: #{e}")
|
244
|
+
end
|
245
|
+
else
|
246
|
+
EventQ.logger.debug { "[#{self.class}] - No on_retry_exceeded block specified." }
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def call_on_retry_block(message)
|
251
|
+
if @on_retry_block
|
252
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_retry block." }
|
253
|
+
begin
|
254
|
+
@on_retry_block.call(message, abort)
|
255
|
+
rescue => e
|
256
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry block. Error: #{e}")
|
257
|
+
end
|
258
|
+
else
|
259
|
+
EventQ.logger.debug { "[#{self.class}] - No on_retry block specified." }
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def reject_message(channel, message, delivery_tag, retry_exchange, queue, abort)
|
264
|
+
|
265
|
+
EventQ.logger.info("[#{self.class}] - Message rejected removing from queue.")
|
266
|
+
#reject the message to remove from queue
|
267
|
+
channel.reject(delivery_tag, false)
|
268
|
+
|
269
|
+
#check if the message retry limit has been exceeded
|
270
|
+
if message.retry_attempts >= queue.max_retry_attempts
|
271
|
+
|
272
|
+
EventQ.logger.info("[#{self.class}] - Message retry attempt limit exceeded. Msg: #{serialize_message(message)}")
|
273
|
+
|
274
|
+
call_on_retry_exceeded_block(message)
|
275
|
+
|
276
|
+
#check if the message is allowed to be retried
|
277
|
+
elsif queue.allow_retry
|
278
|
+
|
279
|
+
EventQ.logger.debug { "[#{self.class}] - Incrementing retry attempts count." }
|
280
|
+
message.retry_attempts += 1
|
281
|
+
|
282
|
+
if queue.allow_retry_back_off == true
|
283
|
+
EventQ.logger.debug { "[#{self.class}] - Calculating message back off retry delay. Attempts: #{message.retry_attempts} * Retry Delay: #{queue.retry_delay}" }
|
284
|
+
message_ttl = message.retry_attempts * queue.retry_delay
|
285
|
+
if (message.retry_attempts * queue.retry_delay) > queue.max_retry_delay
|
286
|
+
EventQ.logger.debug { "[#{self.class}] - Max message back off retry delay reached." }
|
287
|
+
message_ttl = queue.max_retry_delay
|
288
|
+
end
|
289
|
+
else
|
290
|
+
EventQ.logger.debug { "[#{self.class}] - Setting fixed retry delay for message." }
|
291
|
+
message_ttl = queue.retry_delay
|
292
|
+
end
|
293
|
+
|
294
|
+
EventQ.logger.debug { "[#{self.class}] - Sending message for retry. Message TTL: #{message_ttl}" }
|
295
|
+
retry_exchange.publish(serialize_message(message), :expiration => message_ttl)
|
296
|
+
EventQ.logger.debug { "[#{self.class}] - Published message to retry exchange." }
|
297
|
+
|
298
|
+
call_on_retry_block(message)
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
return true
|
303
|
+
|
304
|
+
end
|
305
|
+
|
306
|
+
def configure(queue, options = {})
|
307
|
+
|
308
|
+
@queue = queue
|
309
|
+
|
310
|
+
#default thread count
|
311
|
+
@thread_count = 4
|
312
|
+
if options.key?(:thread_count)
|
313
|
+
@thread_count = options[:thread_count]
|
314
|
+
end
|
315
|
+
|
316
|
+
#default sleep time in seconds
|
317
|
+
@sleep = 15
|
318
|
+
if options.key?(:sleep)
|
319
|
+
@sleep = options[:sleep]
|
320
|
+
end
|
321
|
+
|
322
|
+
@fork_count = 1
|
323
|
+
if options.key?(:fork_count)
|
324
|
+
@fork_count = options[:fork_count]
|
325
|
+
end
|
326
|
+
|
327
|
+
@gc_flush_interval = 10
|
328
|
+
if options.key?(:gc_flush_interval)
|
329
|
+
@gc_flush_interval = options[:gc_flush_interval]
|
330
|
+
end
|
331
|
+
|
332
|
+
EventQ.logger.info("[#{self.class}] - Configuring. Process Count: #{@fork_count} | Thread Count: #{@thread_count} | Interval Sleep: #{@sleep}.")
|
333
|
+
|
334
|
+
return true
|
335
|
+
|
336
|
+
end
|
337
|
+
|
338
|
+
private
|
339
|
+
|
340
|
+
def process_message(payload, queue, channel, retry_exchange, delivery_tag, block)
|
341
|
+
abort = false
|
342
|
+
error = false
|
343
|
+
message = deserialize_message(payload)
|
344
|
+
|
345
|
+
EventQ.logger.info("[#{self.class}] - Message received. Retry Attempts: #{message.retry_attempts}")
|
346
|
+
|
347
|
+
@signature_provider_manager.validate_signature(message: message, queue: queue)
|
348
|
+
|
349
|
+
message_args = EventQ::MessageArgs.new(type: message.type,
|
350
|
+
retry_attempts: message.retry_attempts,
|
351
|
+
context: message.context,
|
352
|
+
content_type: message.content_type)
|
353
|
+
|
354
|
+
if(!EventQ::NonceManager.is_allowed?(message.id))
|
355
|
+
EventQ.logger.info("[#{self.class}] - Duplicate Message received. Dropping message.")
|
356
|
+
channel.acknowledge(delivery_tag, false)
|
357
|
+
return false
|
358
|
+
end
|
359
|
+
|
360
|
+
#begin worker block for queue message
|
361
|
+
begin
|
362
|
+
block.call(message.content, message_args)
|
363
|
+
|
364
|
+
if message_args.abort == true
|
365
|
+
abort = true
|
366
|
+
EventQ.logger.info("[#{self.class}] - Message aborted.")
|
367
|
+
else
|
368
|
+
#accept the message as processed
|
369
|
+
channel.acknowledge(delivery_tag, false)
|
370
|
+
EventQ.logger.info("[#{self.class}] - Message acknowledged.")
|
371
|
+
end
|
372
|
+
|
373
|
+
rescue => e
|
374
|
+
EventQ.logger.error("[#{self.class}] - An unhandled error happened attempting to process a queue message. Error: #{e} | Backtrace: #{e.backtrace}")
|
375
|
+
error = true
|
376
|
+
call_on_error_block(error: e, message: message)
|
377
|
+
end
|
378
|
+
|
379
|
+
if error || abort
|
380
|
+
EventQ::NonceManager.failed(message.id)
|
381
|
+
reject_message(channel, message, delivery_tag, retry_exchange, queue, abort)
|
382
|
+
else
|
383
|
+
EventQ::NonceManager.complete(message.id)
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module EventQ
|
2
|
+
module RabbitMq
|
3
|
+
class StatusChecker
|
4
|
+
|
5
|
+
def initialize(client:, queue_manager:)
|
6
|
+
|
7
|
+
if client == nil
|
8
|
+
raise 'client must be specified.'.freeze
|
9
|
+
end
|
10
|
+
|
11
|
+
@client = client
|
12
|
+
|
13
|
+
if queue_manager == nil
|
14
|
+
raise 'queue_manager must be specified.'.freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
@queue_manager = queue_manager
|
18
|
+
|
19
|
+
@event_raised_exchange = EventRaisedExchange.new
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def queue?(queue)
|
24
|
+
|
25
|
+
outcome = true
|
26
|
+
|
27
|
+
begin
|
28
|
+
connection = @client.get_connection
|
29
|
+
channel = connection.create_channel
|
30
|
+
_queue_name = EventQ.create_queue_name(queue.name)
|
31
|
+
channel.queue(_queue_name, :durable => true)
|
32
|
+
rescue
|
33
|
+
outcome = false
|
34
|
+
ensure
|
35
|
+
channel.close if channel
|
36
|
+
connection.close if connection
|
37
|
+
end
|
38
|
+
|
39
|
+
outcome
|
40
|
+
end
|
41
|
+
|
42
|
+
def event_type?(event_type)
|
43
|
+
|
44
|
+
outcome = true
|
45
|
+
|
46
|
+
begin
|
47
|
+
connection = @client.get_connection
|
48
|
+
channel = connection.create_channel
|
49
|
+
@queue_manager.get_exchange(channel, @event_raised_exchange)
|
50
|
+
rescue
|
51
|
+
outcome = false
|
52
|
+
ensure
|
53
|
+
channel.close if channel
|
54
|
+
connection.close if connection
|
55
|
+
end
|
56
|
+
|
57
|
+
outcome
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module EventQ
|
2
|
+
module RabbitMq
|
3
|
+
class SubscriptionManager
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
if options[:client] == nil
|
7
|
+
raise ':client (QueueClient) must be specified.'.freeze
|
8
|
+
end
|
9
|
+
@client = options[:client]
|
10
|
+
@queue_manager = QueueManager.new
|
11
|
+
@event_raised_exchange = EventQ::EventRaisedExchange.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def subscribe(event_type, queue)
|
15
|
+
|
16
|
+
_event_type = EventQ.create_event_type(event_type)
|
17
|
+
|
18
|
+
connection = @client.get_connection
|
19
|
+
channel = connection.create_channel
|
20
|
+
|
21
|
+
queue = @queue_manager.get_queue(channel, queue)
|
22
|
+
exchange = @queue_manager.get_exchange(channel, @event_raised_exchange)
|
23
|
+
|
24
|
+
queue.bind(exchange, :routing_key => _event_type)
|
25
|
+
|
26
|
+
channel.close
|
27
|
+
connection.close
|
28
|
+
|
29
|
+
EventQ.logger.debug do
|
30
|
+
"[#{self.class} #subscribe] - Subscribing queue: #{EventQ.create_queue_name(queue.name)} to Exchange: #{_event_type}"
|
31
|
+
end
|
32
|
+
|
33
|
+
return true
|
34
|
+
end
|
35
|
+
|
36
|
+
def unsubscribe(queue)
|
37
|
+
|
38
|
+
connection = @client.get_connection
|
39
|
+
channel = connection.create_channel
|
40
|
+
|
41
|
+
queue = @queue_manager.get_queue(channel, queue)
|
42
|
+
exchange = @queue_manager.get_exchange(channel, @event_raised_exchange)
|
43
|
+
|
44
|
+
queue.unbind(exchange)
|
45
|
+
|
46
|
+
channel.close
|
47
|
+
connection.close
|
48
|
+
|
49
|
+
return true
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'eventq_base'
|
2
|
+
if RUBY_PLATFORM =~ /java/
|
3
|
+
require 'march_hare'
|
4
|
+
else
|
5
|
+
require 'bunny'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'hash_kit'
|
9
|
+
require_relative '../lib/eventq_rabbitmq/version'
|
10
|
+
require_relative '../lib/eventq_rabbitmq/rabbitmq_queue_client'
|
11
|
+
require_relative '../lib/eventq_rabbitmq/rabbitmq_queue_manager'
|
12
|
+
|
13
|
+
if RUBY_PLATFORM =~ /java/
|
14
|
+
require_relative '../lib/eventq_rabbitmq/jruby/rabbitmq_queue_worker'
|
15
|
+
else
|
16
|
+
require_relative '../lib/eventq_rabbitmq/rabbitmq_queue_worker'
|
17
|
+
end
|
18
|
+
|
19
|
+
require_relative '../lib/eventq_rabbitmq/rabbitmq_subscription_manager'
|
20
|
+
require_relative '../lib/eventq_rabbitmq/rabbitmq_eventq_client'
|
21
|
+
require_relative '../lib/eventq_rabbitmq/default_queue'
|
22
|
+
require_relative '../lib/eventq_rabbitmq/rabbitmq_status_checker'
|
23
|
+
|
24
|
+
module EventQ
|
25
|
+
def self.namespace
|
26
|
+
@namespace
|
27
|
+
end
|
28
|
+
def self.namespace=(value)
|
29
|
+
@namespace = value
|
30
|
+
end
|
31
|
+
def self.create_event_type(event_type)
|
32
|
+
if EventQ.namespace == nil
|
33
|
+
return event_type
|
34
|
+
end
|
35
|
+
return "#{EventQ.namespace}-#{event_type}"
|
36
|
+
end
|
37
|
+
def self.create_queue_name(queue_name)
|
38
|
+
if EventQ.namespace == nil
|
39
|
+
return queue_name
|
40
|
+
end
|
41
|
+
return "#{EventQ.namespace}-#{queue_name}"
|
42
|
+
end
|
43
|
+
def self.create_exchange_name(exchange_name)
|
44
|
+
if EventQ.namespace == nil
|
45
|
+
return exchange_name
|
46
|
+
end
|
47
|
+
return "#{EventQ.namespace}-#{exchange_name}"
|
48
|
+
end
|
49
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: eventq_rabbitmq
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.17.0
|
5
|
+
platform: java
|
6
|
+
authors:
|
7
|
+
- vaughanbrittonsage
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-06-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '1.11'
|
19
|
+
name: bundler
|
20
|
+
prerelease: false
|
21
|
+
type: :development
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '10.0'
|
33
|
+
name: rake
|
34
|
+
prerelease: false
|
35
|
+
type: :development
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
name: rspec
|
48
|
+
prerelease: false
|
49
|
+
type: :development
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '1.15'
|
61
|
+
name: eventq_base
|
62
|
+
prerelease: false
|
63
|
+
type: :runtime
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.15'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
name: march_hare
|
76
|
+
prerelease: false
|
77
|
+
type: :runtime
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: This is the rabbitmq implementation for EventQ
|
84
|
+
email:
|
85
|
+
- vaughanbritton@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- bin/console
|
91
|
+
- bin/setup
|
92
|
+
- lib/eventq_rabbitmq.rb
|
93
|
+
- lib/eventq_rabbitmq/default_queue.rb
|
94
|
+
- lib/eventq_rabbitmq/jruby/rabbitmq_queue_worker.rb
|
95
|
+
- lib/eventq_rabbitmq/rabbitmq_eventq_client.rb
|
96
|
+
- lib/eventq_rabbitmq/rabbitmq_queue_client.rb
|
97
|
+
- lib/eventq_rabbitmq/rabbitmq_queue_manager.rb
|
98
|
+
- lib/eventq_rabbitmq/rabbitmq_queue_worker.rb
|
99
|
+
- lib/eventq_rabbitmq/rabbitmq_status_checker.rb
|
100
|
+
- lib/eventq_rabbitmq/rabbitmq_subscription_manager.rb
|
101
|
+
- lib/eventq_rabbitmq/version.rb
|
102
|
+
homepage: https://github.com/vaughanbrittonsage/eventq
|
103
|
+
licenses:
|
104
|
+
- MIT
|
105
|
+
metadata: {}
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 2.6.11
|
123
|
+
signing_key:
|
124
|
+
specification_version: 4
|
125
|
+
summary: This is the rabbitmq implementation for EventQ
|
126
|
+
test_files: []
|