euston-rabbitmq 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/Gemfile +2 -0
  2. data/Rakefile +0 -21
  3. data/euston-rabbitmq.gemspec +26 -37
  4. data/lib/euston-rabbitmq/{bindings → euston}/command_handler_binder.rb +2 -2
  5. data/lib/euston-rabbitmq/{errors.rb → euston/errors.rb} +1 -1
  6. data/lib/euston-rabbitmq/{bindings → euston}/event_handler_binder.rb +4 -4
  7. data/lib/euston-rabbitmq/{exchanges.rb → euston/exchanges.rb} +1 -1
  8. data/lib/euston-rabbitmq/{bindings → euston}/handler_binder.rb +2 -1
  9. data/lib/euston-rabbitmq/{queues.rb → euston/queues.rb} +1 -1
  10. data/lib/euston-rabbitmq/{subscriptions/retriable_subscription.rb → euston/retrying_subscription.rb} +17 -16
  11. data/lib/euston-rabbitmq/rabbitmq_client/queue.rb +70 -0
  12. data/lib/euston-rabbitmq/rabbitmq_client/reactive_message.rb +15 -0
  13. data/lib/euston-rabbitmq/{constant_loader.rb → reflection/constant_loader.rb} +0 -0
  14. data/lib/euston-rabbitmq/{handler_finder.rb → reflection/handler_finder.rb} +0 -0
  15. data/lib/euston-rabbitmq/{handler_reference.rb → reflection/handler_reference.rb} +0 -0
  16. data/lib/euston-rabbitmq/version.rb +1 -1
  17. data/lib/euston-rabbitmq.rb +8 -22
  18. data/spec/euston/command_handler_binder_spec.rb +24 -0
  19. data/spec/euston/event_handler_binder_spec.rb +36 -0
  20. data/spec/euston/exchanges_spec.rb +27 -0
  21. data/spec/euston/queues_spec.rb +24 -0
  22. data/spec/euston/retrying_subscription_spec.rb +74 -0
  23. data/spec/rabbitmq_client/queue_spec.rb +69 -0
  24. data/spec/{constant_loader_spec.rb → reflection/constant_loader_spec.rb} +3 -1
  25. data/spec/{handler_finder_spec.rb → reflection/handler_finder_spec.rb} +3 -1
  26. data/spec/spec_helper.rb +19 -52
  27. data/spec/support/filters.rb +10 -0
  28. data/spec/support/queue_subscription_thread_harness.rb +29 -0
  29. data/spec/support/rabbitmqadmin.rb +74 -0
  30. metadata +58 -117
  31. data/lib/euston-rabbitmq/command_handlers/retry_failed_message.rb +0 -29
  32. data/lib/euston-rabbitmq/event_handlers/message_failure.rb +0 -27
  33. data/lib/euston-rabbitmq/message_buffer.rb +0 -67
  34. data/lib/euston-rabbitmq/message_logger.rb +0 -50
  35. data/lib/euston-rabbitmq/queue.rb +0 -30
  36. data/lib/euston-rabbitmq/read_model/failed_message.rb +0 -36
  37. data/lib/euston-rabbitmq/read_model/message_buffer.rb +0 -57
  38. data/lib/euston-rabbitmq/read_model/message_log.rb +0 -37
  39. data/spec/command_buffer_spec.rb +0 -69
  40. data/spec/event_buffer_spec.rb +0 -69
  41. data/spec/exchange_declaration_spec.rb +0 -28
  42. data/spec/message_failure_spec.rb +0 -77
  43. data/spec/mt_safe_queue_subscription_spec.rb +0 -72
  44. data/spec/safe_queue_subscription_spec.rb +0 -50
  45. data/spec/support/factories.rb +0 -18
data/Gemfile CHANGED
@@ -1,2 +1,4 @@
1
1
  source :rubygems
2
2
  gemspec
3
+
4
+ gem 'safely', :git => 'https://github.com/leemhenson/safely.git', :branch => 'override_strategies'
data/Rakefile CHANGED
@@ -78,27 +78,6 @@ RSpec::Core::RakeTask.new(:spec) do |t|
78
78
  t.rspec_opts = default_rspec_opts
79
79
  end
80
80
 
81
- desc "Resets the testing vhost in rabbitmq"
82
- task :reset_rabbitmq do
83
- vhosts = `rabbitmqctl list_vhosts`.split("\n")
84
- vhosts = trim_array_ends vhosts
85
- vhost = '/euston-rabbitmq-test'
86
-
87
- puts `rabbitmqctl delete_vhost #{vhost}` if vhosts.include? vhost
88
- puts `rabbitmqctl add_vhost #{vhost}`
89
-
90
- users = `rabbitmqctl list_users`.split("\n")
91
- users = trim_array_ends users
92
- users = users.map { |u| u.split("\t").shift }
93
-
94
- user, password = 'euston-rabbitmq-tester', 'password'
95
-
96
- puts `rabbitmqctl delete_user #{user}` if users.include? user
97
- puts `rabbitmqctl add_user #{user} #{password}`
98
- puts `rabbitmqctl set_permissions -p #{vhost} #{user} ".*" ".*" ".*"`
99
- puts `rabbitmqctl set_permissions -p #{vhost} guest ".*" ".*" ".*"` if users.include? 'guest'
100
- end
101
-
102
81
  #############################################################################
103
82
  #
104
83
  # Packaging tasks
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'euston-rabbitmq'
3
- s.version = '1.0.1'
3
+ s.version = '1.0.2'
4
4
  s.platform = RUBY_PLATFORM.to_s == 'java' ? 'java' : Gem::Platform::RUBY
5
5
  s.authors = ['Lee Henson', 'Guy Boertje']
6
6
  s.email = ['lee.m.henson@gmail.com', 'guyboertje@gmail.com']
@@ -14,35 +14,31 @@ Gem::Specification.new do |s|
14
14
  Rakefile
15
15
  euston-rabbitmq.gemspec
16
16
  lib/euston-rabbitmq.rb
17
- lib/euston-rabbitmq/bindings/command_handler_binder.rb
18
- lib/euston-rabbitmq/bindings/event_handler_binder.rb
19
- lib/euston-rabbitmq/bindings/handler_binder.rb
20
- lib/euston-rabbitmq/command_handlers/retry_failed_message.rb
21
- lib/euston-rabbitmq/constant_loader.rb
22
- lib/euston-rabbitmq/errors.rb
23
- lib/euston-rabbitmq/event_handlers/message_failure.rb
24
- lib/euston-rabbitmq/exchanges.rb
25
- lib/euston-rabbitmq/handler_finder.rb
26
- lib/euston-rabbitmq/handler_reference.rb
27
- lib/euston-rabbitmq/message_buffer.rb
28
- lib/euston-rabbitmq/message_logger.rb
29
- lib/euston-rabbitmq/queue.rb
30
- lib/euston-rabbitmq/queues.rb
31
- lib/euston-rabbitmq/read_model/failed_message.rb
32
- lib/euston-rabbitmq/read_model/message_buffer.rb
33
- lib/euston-rabbitmq/read_model/message_log.rb
34
- lib/euston-rabbitmq/subscriptions/retriable_subscription.rb
17
+ lib/euston-rabbitmq/euston/command_handler_binder.rb
18
+ lib/euston-rabbitmq/euston/errors.rb
19
+ lib/euston-rabbitmq/euston/event_handler_binder.rb
20
+ lib/euston-rabbitmq/euston/exchanges.rb
21
+ lib/euston-rabbitmq/euston/handler_binder.rb
22
+ lib/euston-rabbitmq/euston/queues.rb
23
+ lib/euston-rabbitmq/euston/retrying_subscription.rb
24
+ lib/euston-rabbitmq/rabbitmq_client/queue.rb
25
+ lib/euston-rabbitmq/rabbitmq_client/reactive_message.rb
26
+ lib/euston-rabbitmq/reflection/constant_loader.rb
27
+ lib/euston-rabbitmq/reflection/handler_finder.rb
28
+ lib/euston-rabbitmq/reflection/handler_reference.rb
35
29
  lib/euston-rabbitmq/version.rb
36
- spec/command_buffer_spec.rb
37
- spec/constant_loader_spec.rb
38
- spec/event_buffer_spec.rb
39
- spec/exchange_declaration_spec.rb
40
- spec/handler_finder_spec.rb
41
- spec/message_failure_spec.rb
42
- spec/mt_safe_queue_subscription_spec.rb
43
- spec/safe_queue_subscription_spec.rb
30
+ spec/euston/command_handler_binder_spec.rb
31
+ spec/euston/event_handler_binder_spec.rb
32
+ spec/euston/exchanges_spec.rb
33
+ spec/euston/queues_spec.rb
34
+ spec/euston/retrying_subscription_spec.rb
35
+ spec/rabbitmq_client/queue_spec.rb
36
+ spec/reflection/constant_loader_spec.rb
37
+ spec/reflection/handler_finder_spec.rb
44
38
  spec/spec_helper.rb
45
- spec/support/factories.rb
39
+ spec/support/filters.rb
40
+ spec/support/queue_subscription_thread_harness.rb
41
+ spec/support/rabbitmqadmin.rb
46
42
  ]
47
43
  # = MANIFEST =
48
44
 
@@ -50,27 +46,20 @@ Gem::Specification.new do |s|
50
46
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
51
47
 
52
48
  s.add_dependency 'activesupport', '~> 3.0.0'
53
- s.add_dependency 'euston', '~> 1.0.0'
49
+ s.add_dependency 'euston', '~> 1.0.1'
54
50
  s.add_dependency 'euston-eventstore', '~> 1.0.0'
55
51
  s.add_dependency 'hash-keys', '~> 1.0.0'
56
52
  s.add_dependency 'hollywood', '~> 1.0.0'
53
+ s.add_dependency 'i18n', '~> 0.6.0'
57
54
  s.add_dependency 'require_all', '~> 1.2.0'
58
55
  s.add_dependency 'robustthread', '~> 0.5.2'
59
56
  s.add_dependency 'safely', '~> 0.3.0'
60
57
 
61
58
  if RUBY_PLATFORM.to_s == 'java'
62
- s.add_dependency 'jmongo', '~> 1.0.0'
63
59
  s.add_dependency 'jessica', '~> 1.0.0'
64
- else
65
- s.add_dependency 'amqp', '~> 0.8.0'
66
- s.add_dependency 'bson_ext', '~> 1.3.1'
67
- s.add_dependency 'eventmachine', '~> 0.12.10'
68
- s.add_dependency 'mongo', '~> 1.3.1'
69
- s.add_development_dependency 'evented-spec', '~> 0.9.0'
70
60
  end
71
61
 
72
62
  s.add_development_dependency 'awesome_print', '~> 0.4.0'
73
- s.add_development_dependency 'faker', '~> 1.0.0'
74
63
  s.add_development_dependency 'fuubar', '~> 0.0.0'
75
64
  s.add_development_dependency 'rspec', '~> 2.6.0'
76
65
  end
@@ -9,14 +9,14 @@ module Euston
9
9
 
10
10
  routing_key = "commands.#{reference.name.to_s.underscore}"
11
11
 
12
- EUSTON_LOG.debug "Ensuring routing key exists for queue #{queue_name}: #{routing_key}"
12
+ @log.debug "Ensuring routing key exists for queue #{queue_name}: #{routing_key}"
13
13
 
14
14
  exchange = get_exchange channel, :commands
15
15
  queue.bind exchange, :routing_key => routing_key
16
16
  end
17
17
 
18
18
  def get_command_handler_queue channel, queue_name
19
- EUSTON_LOG.debug "Ensuring command handler queue exists: #{queue_name}" if @command_handler_queue.nil?
19
+ @log.debug "Ensuring command handler queue exists: #{queue_name}" if @command_handler_queue.nil?
20
20
  @command_handler_queue ||= get_queue channel, queue_name
21
21
  end
22
22
  end
@@ -2,4 +2,4 @@ module Euston
2
2
  module RabbitMq
3
3
  class MessageDecodeFailedError < StandardError; end
4
4
  end
5
- end
5
+ end
@@ -6,7 +6,7 @@ module Euston
6
6
  def ensure_bindings_exist_for_reference channel, reference
7
7
  queue_name = reference.name.to_s.underscore
8
8
 
9
- EUSTON_LOG.debug "Ensuring event handler queue exists: #{queue_name}"
9
+ @log.debug "Ensuring event handler queue exists: #{queue_name}"
10
10
 
11
11
  queue = get_queue channel, queue_name
12
12
 
@@ -14,15 +14,15 @@ module Euston
14
14
 
15
15
  methods = reference.handler.public_instance_methods(false)
16
16
  methods = methods.select { |method| method.to_s.start_with? prefix }
17
- methods = methods.map { |method| method.to_s[prefix.length, method.to_s.length - prefix.length] }
18
- methods = methods.map { |method| method.split('__').first }
17
+ methods = methods.map { |method| method.to_s[prefix.length, method.to_s.length - prefix.length] }
18
+ methods = methods.map { |method| method.split('__').first }
19
19
 
20
20
  exchange = get_exchange channel, :events
21
21
 
22
22
  methods.uniq.each do |method|
23
23
  routing_key = "events.#{method}"
24
24
 
25
- EUSTON_LOG.debug "Ensuring routing key exists for queue #{queue_name}: #{routing_key}"
25
+ @log.debug "Ensuring routing key exists for queue #{queue_name}: #{routing_key}"
26
26
 
27
27
  queue.bind exchange, :routing_key => routing_key
28
28
  end
@@ -14,4 +14,4 @@ module Euston
14
14
  end
15
15
  end
16
16
  end
17
- end
17
+ end
@@ -4,8 +4,9 @@ module Euston
4
4
  include Euston::RabbitMq::Queues
5
5
  include Euston::RabbitMq::Exchanges
6
6
 
7
- def initialize references
7
+ def initialize references, logger = Euston::NullLogger.instance
8
8
  @references = references
9
+ @log = logger
9
10
  end
10
11
 
11
12
  def ensure_bindings_exist
@@ -10,4 +10,4 @@ module Euston
10
10
  end
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -1,16 +1,17 @@
1
1
  module Euston
2
2
  module RabbitMq
3
- class RetriableSubscription
3
+ class RetryingSubscription
4
4
  include Hollywood
5
5
  include Euston::RabbitMq::Queues
6
6
  include Euston::RabbitMq::Exchanges
7
7
 
8
- def initialize channel, queue_name
8
+ def initialize channel, queue_name, logger = Euston::NullLogger.instance
9
9
  @channel = channel
10
10
  @queue_name = queue_name
11
+ @log = logger
11
12
  end
12
13
 
13
- def attach_queue_hook_listeners
14
+ def subscribe
14
15
  queue.when(:message_decode_failed => method(:log_decode_failure),
15
16
  :message_failed => method(:handle_failure),
16
17
  :message_received => method(:call_handler))
@@ -20,11 +21,11 @@ module Euston
20
21
 
21
22
  private
22
23
 
23
- def call_handler(message)
24
+ def call_handler message
24
25
  callback :message_received, message
25
26
  end
26
27
 
27
- def create_message_failed_message error, failed_message, amqp_header
28
+ def create_message_failed_message error, failed_message, reactive_message
28
29
  {
29
30
  :headers =>
30
31
  {
@@ -37,14 +38,14 @@ module Euston
37
38
  :body =>
38
39
  {
39
40
  :message => failed_message,
40
- :routing_key => amqp_header.method.routing_key,
41
+ :routing_key => reactive_message.method.routing_key,
41
42
  :error => error.message,
42
43
  :backtrace => error.backtrace
43
44
  }
44
45
  }
45
46
  end
46
47
 
47
- def handle_failure message, error, amqp_header
48
+ def handle_failure message, error, reactive_message
48
49
  failures = message[:failures] || 0
49
50
  failures = failures + 1
50
51
  message[:failures] = failures
@@ -54,38 +55,38 @@ module Euston
54
55
  debug_message = "Message failed, out of retries"
55
56
 
56
57
  message.delete :failures
57
- message = create_message_failed_message error, message, amqp_header
58
+ message = create_message_failed_message error, message, reactive_message
58
59
 
59
60
  options = { :key => 'events.message_failed' }
60
61
  exchange = :events
61
62
  else
62
63
  debug_message = "Message failed, retrying"
63
64
 
64
- options = { :key => amqp_header.method.routing_key }
65
- exchange = amqp_header.method.routing_key.split('.').first.to_sym
65
+ options = { :key => reactive_message.method.routing_key }
66
+ exchange = reactive_message.method.routing_key.split('.').first.to_sym
66
67
  end
67
68
 
68
69
  options = default_publish_options.merge options
69
70
  exchange = get_exchange @channel, exchange
70
71
  message = ActiveSupport::JSON.encode message
71
72
 
72
- EUSTON_LOG.debug "#{debug_message}: #{message}"
73
+ @log.debug "#{debug_message}: #{message}"
73
74
 
74
75
  exchange.publish message, options
75
76
 
76
- amqp_header.ack
77
+ reactive_message.ack
77
78
  rescue StandardError => e
78
- amqp_header.reject :requeue => true
79
+ reactive_message.reject :requeue => true
79
80
  raise e
80
81
  end
81
82
  end
82
83
 
83
84
  def log_decode_failure message, error
84
85
  text = "A handler queue subscription failed. [Error] #{error.message} [Payload] #{message}"
85
- err = Euston::RabbitMq::MessageDecodeFailedError.new text
86
- err.set_backtrace error.backtrace
86
+ error = Euston::RabbitMq::MessageDecodeFailedError.new text
87
+ error.set_backtrace error.backtrace
87
88
 
88
- Safely.report! err
89
+ raise error
89
90
  end
90
91
 
91
92
  def queue
@@ -0,0 +1,70 @@
1
+ class RabbitMQClient
2
+ class Queue
3
+ include Hollywood
4
+
5
+ attr_writer :timeout
6
+
7
+ def delivery_timeout
8
+ @timeout ||= 500
9
+ end
10
+
11
+ def safe_subscribe
12
+ _consumer = self.consumer
13
+
14
+ until Thread.current[:stop] do
15
+ safe_subscribe_with_timeout(_consumer, self.delivery_timeout)
16
+ end
17
+ end
18
+
19
+ def safe_handle_message reactive_message
20
+ begin
21
+ message = parse_json reactive_message.body
22
+
23
+ begin
24
+ callback :message_received, message
25
+ reactive_message.ack!
26
+ rescue Euston::EventStore::ConcurrencyError
27
+ reactive_message.reject! true #requeue
28
+ rescue => e
29
+ callback :message_failed, message, e, reactive_message
30
+ Safely.report! e
31
+ end
32
+ rescue => e
33
+ callback :message_decode_failed, reactive_message.body, e
34
+ reactive_message.ack!
35
+ Safely.report! e
36
+ end
37
+ end
38
+
39
+ def consumer auto_ack = false
40
+ consumer = QueueingConsumer.new @channel
41
+ @channel.basic_consume @name, auto_ack, consumer
42
+ consumer
43
+ end
44
+
45
+ def safe_subscribe_with_timeout consumer, timeout = 500
46
+ loop do
47
+ delivery = nil
48
+ begin
49
+ delivery = consumer.next_delivery timeout
50
+ rescue NativeException => e
51
+ Thread.current[:exception] = e
52
+ break
53
+ end
54
+
55
+ break if delivery.nil?
56
+
57
+ reactive_message = ReactiveMessage.new @channel, delivery, String.from_java_bytes(delivery.get_body)
58
+ safe_handle_message reactive_message
59
+
60
+ @channel.basic_ack(delivery.envelope.delivery_tag, false) if reactive_message.should_acknowledge?
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def parse_json json
67
+ JSON.parse json, :symbolize_names => true
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,15 @@
1
+ class RabbitMQClient
2
+ class ReactiveMessage
3
+ def reject opts = {}
4
+ self.reject!(opts.fetch :requeue, true)
5
+ end
6
+
7
+ def ack multiple = false
8
+ self.ack!
9
+ end
10
+
11
+ def method
12
+ self.envelope
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  module Euston
2
2
  module RabbitMq
3
- VERSION = "1.0.1"
3
+ VERSION = "1.0.2"
4
4
  end
5
5
  end
@@ -1,30 +1,16 @@
1
- require 'require_all'
2
- require 'active_support/core_ext/hash/keys'
3
1
  require 'active_support/core_ext/string/inflections'
4
2
  require 'active_support/json'
5
3
  require 'active_support/ordered_hash'
6
- require 'robustthread'
7
-
8
- if RUBY_PLATFORM == 'java'
9
- require 'jessica'
10
- else
11
- require 'eventmachine'
12
- require 'amqp'
13
- end
14
-
15
4
  require 'hash-keys'
16
5
  require 'hollywood'
6
+ require 'i18n'
7
+ require 'jessica' if RUBY_PLATFORM == 'java'
8
+ require 'require_all'
9
+ require 'safely'
10
+
17
11
  require 'euston'
18
12
  require 'euston-eventstore'
19
13
 
20
- require_rel 'euston-rabbitmq/exchanges.rb'
21
- require_rel 'euston-rabbitmq/queues.rb'
22
- require_rel 'euston-rabbitmq/**/*.rb'
23
-
24
- module Euston
25
- module RabbitMq
26
- class << self
27
- attr_accessor :event_store, :event_store_mongodb, :read_model_mongodb
28
- end
29
- end
30
- end
14
+ require_rel 'euston-rabbitmq/reflection'
15
+ require_rel 'euston-rabbitmq/rabbitmq_client'
16
+ require_rel 'euston-rabbitmq/euston'