euston-rabbitmq 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'euston-rabbitmq'
3
- s.version = '1.0.0'
3
+ s.version = '1.0.1'
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']
@@ -11,20 +11,19 @@ Gem::Specification.new do |s|
11
11
  # = MANIFEST =
12
12
  s.files = %w[
13
13
  Gemfile
14
- Gemfile.lock
15
14
  Rakefile
16
15
  euston-rabbitmq.gemspec
17
16
  lib/euston-rabbitmq.rb
18
- lib/euston-rabbitmq/buffered_message_dispatcher.rb
19
- lib/euston-rabbitmq/command_handler_bindings.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
20
  lib/euston-rabbitmq/command_handlers/retry_failed_message.rb
21
+ lib/euston-rabbitmq/constant_loader.rb
21
22
  lib/euston-rabbitmq/errors.rb
22
- lib/euston-rabbitmq/event_handler_binding.rb
23
- lib/euston-rabbitmq/event_handler_bindings.rb
24
23
  lib/euston-rabbitmq/event_handlers/message_failure.rb
25
- lib/euston-rabbitmq/event_store_dispatcher.rb
26
24
  lib/euston-rabbitmq/exchanges.rb
27
- lib/euston-rabbitmq/handler_bindings.rb
25
+ lib/euston-rabbitmq/handler_finder.rb
26
+ lib/euston-rabbitmq/handler_reference.rb
28
27
  lib/euston-rabbitmq/message_buffer.rb
29
28
  lib/euston-rabbitmq/message_logger.rb
30
29
  lib/euston-rabbitmq/queue.rb
@@ -32,10 +31,13 @@ Gem::Specification.new do |s|
32
31
  lib/euston-rabbitmq/read_model/failed_message.rb
33
32
  lib/euston-rabbitmq/read_model/message_buffer.rb
34
33
  lib/euston-rabbitmq/read_model/message_log.rb
34
+ lib/euston-rabbitmq/subscriptions/retriable_subscription.rb
35
35
  lib/euston-rabbitmq/version.rb
36
36
  spec/command_buffer_spec.rb
37
+ spec/constant_loader_spec.rb
37
38
  spec/event_buffer_spec.rb
38
39
  spec/exchange_declaration_spec.rb
40
+ spec/handler_finder_spec.rb
39
41
  spec/message_failure_spec.rb
40
42
  spec/mt_safe_queue_subscription_spec.rb
41
43
  spec/safe_queue_subscription_spec.rb
@@ -0,0 +1,24 @@
1
+ module Euston
2
+ module RabbitMq
3
+ class CommandHandlerBinder < HandlerBinder
4
+ private
5
+
6
+ def ensure_bindings_exist_for_reference channel, reference
7
+ queue_name = :command_handlers
8
+ queue = get_command_handler_queue channel, queue_name
9
+
10
+ routing_key = "commands.#{reference.name.to_s.underscore}"
11
+
12
+ EUSTON_LOG.debug "Ensuring routing key exists for queue #{queue_name}: #{routing_key}"
13
+
14
+ exchange = get_exchange channel, :commands
15
+ queue.bind exchange, :routing_key => routing_key
16
+ end
17
+
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?
20
+ @command_handler_queue ||= get_queue channel, queue_name
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,32 @@
1
+ module Euston
2
+ module RabbitMq
3
+ class EventHandlerBinder < HandlerBinder
4
+ private
5
+
6
+ def ensure_bindings_exist_for_reference channel, reference
7
+ queue_name = reference.name.to_s.underscore
8
+
9
+ EUSTON_LOG.debug "Ensuring event handler queue exists: #{queue_name}"
10
+
11
+ queue = get_queue channel, queue_name
12
+
13
+ prefix = '__event_handler__'
14
+
15
+ methods = reference.handler.public_instance_methods(false)
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 }
19
+
20
+ exchange = get_exchange channel, :events
21
+
22
+ methods.uniq.each do |method|
23
+ routing_key = "events.#{method}"
24
+
25
+ EUSTON_LOG.debug "Ensuring routing key exists for queue #{queue_name}: #{routing_key}"
26
+
27
+ queue.bind exchange, :routing_key => routing_key
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ module Euston
2
+ module RabbitMq
3
+ class HandlerBinder
4
+ include Euston::RabbitMq::Queues
5
+ include Euston::RabbitMq::Exchanges
6
+
7
+ def initialize references
8
+ @references = references
9
+ end
10
+
11
+ def ensure_bindings_exist
12
+ begin
13
+ channel = AMQP::Channel.new
14
+ channel.prefetch 1
15
+
16
+ @references.each do |reference|
17
+ ensure_bindings_exist_for_reference channel, reference
18
+ end
19
+ ensure
20
+ channel.disconnect unless channel.nil?
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ module Euston
2
+ module RabbitMq
3
+ class ConstantLoader
4
+ include Hollywood
5
+
6
+ def load string
7
+ namespace = Object
8
+ found = true
9
+
10
+ string.split('::').each do |segment|
11
+ if found && namespace.const_defined?(segment)
12
+ namespace = namespace.const_get segment.to_sym
13
+ else
14
+ found = false
15
+ end
16
+ end
17
+
18
+ if found
19
+ callback :hit, namespace
20
+ else
21
+ callback :miss, string
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,57 @@
1
+ module Euston
2
+ module RabbitMq
3
+ class HandlerFinder
4
+ def initialize required_mixins = []
5
+ @namespaces = []
6
+ @constant_loader = ConstantLoader.new.when(:hit => method(:store_found_constant), :miss => method(:log_failed_lookup))
7
+ @required_mixins = required_mixins
8
+ end
9
+
10
+ attr_reader :namespaces
11
+
12
+ def find
13
+ filter_namespaces_list
14
+ map_namespaces_to_references
15
+ end
16
+
17
+ private
18
+
19
+ def filter_namespaces_list
20
+ @namespaces = @namespaces.map do |namespace|
21
+ @current_constant = nil
22
+
23
+ if namespace.is_a? Module
24
+ @current_constant = namespace
25
+ else
26
+ namespace = namespace.to_s
27
+ @constant_loader.load namespace
28
+ end
29
+
30
+ @current_constant
31
+ end.uniq.to_a - [nil]
32
+ end
33
+
34
+ def log_failed_lookup string
35
+ EUSTON_LOG.warn "Couldn't find handler namespace: #{string}" if Object.const_defined?('EUSTON_LOG')
36
+ end
37
+
38
+ def map_namespaces_to_references
39
+ references = []
40
+
41
+ @namespaces.each do |namespace|
42
+ references.push *(namespace.constants.map do |constant|
43
+ reference = HandlerReference.new namespace, namespace.const_get(constant), constant
44
+ reference = nil unless @required_mixins.all? { |mixin| reference.handler.included_modules.include? mixin }
45
+ reference
46
+ end.to_a - [nil])
47
+ end
48
+
49
+ references
50
+ end
51
+
52
+ def store_found_constant constant
53
+ @current_constant = constant if constant.is_a?(Module)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,11 @@
1
+ module Euston
2
+ module RabbitMq
3
+ class HandlerReference
4
+ def initialize namespace, handler, name
5
+ @namespace, @handler, @name = namespace, handler, name
6
+ end
7
+
8
+ attr_reader :namespace, :handler, :name
9
+ end
10
+ end
11
+ end
@@ -16,7 +16,6 @@ module Euston
16
16
  include Hollywood
17
17
 
18
18
  def initialize channel, exchange_name
19
-
20
19
  @channel = channel
21
20
  @exchange = get_exchange channel, exchange_name
22
21
  @read_model = Euston::RabbitMq::ReadModel::MessageBuffer.send exchange_name
@@ -65,4 +64,4 @@ module Euston
65
64
  end
66
65
  end
67
66
  end
68
- end
67
+ end
@@ -27,6 +27,11 @@ module Euston
27
27
  'json' => ::ActiveSupport::JSON.encode(message) }, :safe => { :fsync => true })
28
28
  end
29
29
 
30
+ def find_next_message
31
+ query = { 'next_attempt' => { '$lte' => Time.now.to_f } }
32
+ @collection.find_one(query)
33
+ end
34
+
30
35
  def find_due_messages
31
36
  query = { 'next_attempt' => { '$lte' => Time.now.to_f } }
32
37
  order = [ 'next_attempt', Mongo::ASCENDING ]
@@ -40,7 +45,7 @@ module Euston
40
45
 
41
46
  def set_next_attempt message
42
47
  @collection.update({ '_id' => message['_id'] },
43
- { '$set' => { 'next_attempt' => message['next_attempt'] + 10 } }, :safe => { :fsync => true })
48
+ { '$set' => { 'next_attempt' => Time.now.to_f + 10 } }, :safe => { :fsync => true })
44
49
  end
45
50
 
46
51
  def remove_published_message id
@@ -49,4 +54,4 @@ module Euston
49
54
  end
50
55
  end
51
56
  end
52
- end
57
+ end
@@ -1,47 +1,16 @@
1
1
  module Euston
2
2
  module RabbitMq
3
- class HandlerBindings
4
- include Euston::RabbitMq::Exchanges
3
+ class RetriableSubscription
4
+ include Hollywood
5
5
  include Euston::RabbitMq::Queues
6
+ include Euston::RabbitMq::Exchanges
6
7
 
7
- def initialize channel
8
+ def initialize channel, queue_name
8
9
  @channel = channel
9
- @exchanges = { :commands => get_exchange(@channel, :commands),
10
- :events => get_exchange(@channel, :events) }
11
- @namespaces = []
12
- end
13
-
14
- def add_namespace namespace
15
- @namespaces << namespace
16
- end
17
-
18
- def namespaced_handler_types
19
- ret = []
20
- @namespaces.each do |namespace|
21
- namespace.constants.each do |handler_type|
22
- ret << [namespace, handler_type]
23
- end
24
- end
25
- ret
26
- end
27
-
28
- def finalize_bindings
29
- namespaced_handler_types.each do |namespace, handler_type|
30
- bind_handler handler_type
31
- end
10
+ @queue_name = queue_name
32
11
  end
33
12
 
34
- protected
35
-
36
- def bind_handler handler_type
37
- # virtual
38
- end
39
-
40
- def find_namespaces_containing_handler_type handler_type
41
- @namespaces.select { |namespace| namespace.const_defined? handler_type }
42
- end
43
-
44
- def attach_queue_hook_listeners queue
13
+ def attach_queue_hook_listeners
45
14
  queue.when(:message_decode_failed => method(:log_decode_failure),
46
15
  :message_failed => method(:handle_failure),
47
16
  :message_received => method(:call_handler))
@@ -49,8 +18,10 @@ module Euston
49
18
  queue.safe_subscribe
50
19
  end
51
20
 
21
+ private
22
+
52
23
  def call_handler(message)
53
- # abstract
24
+ callback :message_received, message
54
25
  end
55
26
 
56
27
  def create_message_failed_message error, failed_message, amqp_header
@@ -80,19 +51,25 @@ module Euston
80
51
 
81
52
  begin
82
53
  if failures == 3
54
+ debug_message = "Message failed, out of retries"
55
+
83
56
  message.delete :failures
84
57
  message = create_message_failed_message error, message, amqp_header
85
58
 
86
59
  options = { :key => 'events.message_failed' }
87
60
  exchange = :events
88
61
  else
62
+ debug_message = "Message failed, retrying"
63
+
89
64
  options = { :key => amqp_header.method.routing_key }
90
65
  exchange = amqp_header.method.routing_key.split('.').first.to_sym
91
66
  end
92
67
 
93
68
  options = default_publish_options.merge options
94
- exchange = @exchanges[exchange]
95
- message = ::ActiveSupport::JSON.encode message
69
+ exchange = get_exchange @channel, exchange
70
+ message = ActiveSupport::JSON.encode message
71
+
72
+ EUSTON_LOG.debug "#{debug_message}: #{message}"
96
73
 
97
74
  exchange.publish message, options
98
75
 
@@ -110,6 +87,10 @@ module Euston
110
87
 
111
88
  Safely.report! err
112
89
  end
90
+
91
+ def queue
92
+ @queue ||= get_queue @channel, @queue_name
93
+ end
113
94
  end
114
95
  end
115
- end
96
+ end
@@ -1,5 +1,5 @@
1
1
  module Euston
2
2
  module RabbitMq
3
- VERSION = "1.0.0"
3
+ VERSION = "1.0.1"
4
4
  end
5
5
  end
@@ -17,7 +17,9 @@ require 'hollywood'
17
17
  require 'euston'
18
18
  require 'euston-eventstore'
19
19
 
20
- require_rel 'euston-rabbitmq'
20
+ require_rel 'euston-rabbitmq/exchanges.rb'
21
+ require_rel 'euston-rabbitmq/queues.rb'
22
+ require_rel 'euston-rabbitmq/**/*.rb'
21
23
 
22
24
  module Euston
23
25
  module RabbitMq
@@ -0,0 +1,38 @@
1
+ require File.expand_path('../spec_helper.rb', __FILE__)
2
+
3
+ module ConstantLoaderTesting
4
+ module SubNamespace
5
+ class Foobar
6
+ end
7
+ end
8
+ end
9
+
10
+ describe 'constant loader' do
11
+ let(:loader) { Euston::RabbitMq::ConstantLoader.new }
12
+ let(:outcome) { { :hit => nil, :miss => nil} }
13
+
14
+ before { loader.when(:hit => ->(constant) { outcome[:hit] = constant }, :miss => ->{ outcome[:miss] = true }) }
15
+
16
+ subject do
17
+ loader.load constant_string
18
+ outcome
19
+ end
20
+
21
+ context 'with a valid constant string' do
22
+ let(:constant_string) { 'ConstantLoaderTesting::SubNamespace::Foobar' }
23
+
24
+ its([:hit]) { should == ConstantLoaderTesting::SubNamespace::Foobar }
25
+ end
26
+
27
+ context 'with a totally invalid constant string' do
28
+ let(:constant_string) { 'Something::Entirely::Made::Up' }
29
+
30
+ its([:miss]) { should == true }
31
+ end
32
+
33
+ context 'with a partially invalid constant string' do
34
+ let(:constant_string) { 'ConstantLoaderTesting::Missing' }
35
+
36
+ its([:miss]) { should == true }
37
+ end
38
+ end
@@ -0,0 +1,48 @@
1
+ require File.expand_path('../spec_helper.rb', __FILE__)
2
+
3
+ module HandlerFinderTesting
4
+ module EmptyNamespace; end
5
+ module SuperSpecialMixin; end
6
+
7
+ module NonEmptyNamespace
8
+ class Handler1; end
9
+ class Handler2; end
10
+
11
+ class Handler3
12
+ include HandlerFinderTesting::SuperSpecialMixin
13
+ end
14
+ end
15
+ end
16
+
17
+ describe 'handler finder' do
18
+ let(:required_mixins) { [] }
19
+ let(:finder) { Euston::RabbitMq::HandlerFinder.new required_mixins }
20
+
21
+ before { finder.namespaces.push *namespaces }
22
+ subject { finder.find }
23
+
24
+ context 'no namespaces are provided' do
25
+ let(:namespaces) { [] }
26
+
27
+ it { should be_empty }
28
+ end
29
+
30
+ context 'a namespace is provided which contains no classes' do
31
+ let(:namespaces) { [HandlerFinderTesting::EmptyNamespace] }
32
+
33
+ it { should be_empty }
34
+ end
35
+
36
+ context 'a namespace is provided with contains some classes' do
37
+ let(:namespaces) { [HandlerFinderTesting::EmptyNamespace, 'HandlerFinderTesting::NonEmptyNamespace'] }
38
+
39
+ it { should have(3).items }
40
+ end
41
+
42
+ context 'a specific mixin is required on each handler' do
43
+ let(:required_mixins) { [HandlerFinderTesting::SuperSpecialMixin] }
44
+ let(:namespaces) { [HandlerFinderTesting::EmptyNamespace, 'HandlerFinderTesting::NonEmptyNamespace'] }
45
+
46
+ it { should have(1).items }
47
+ end
48
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: euston-rabbitmq
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-09-16 00:00:00.000000000 Z
13
+ date: 2011-09-20 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
17
- requirement: &78505630 !ruby/object:Gem::Requirement
17
+ requirement: &79361210 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: 3.0.0
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *78505630
25
+ version_requirements: *79361210
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: euston
28
- requirement: &78505280 !ruby/object:Gem::Requirement
28
+ requirement: &79360880 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ~>
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: 1.0.0
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *78505280
36
+ version_requirements: *79360880
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: euston-eventstore
39
- requirement: &78504740 !ruby/object:Gem::Requirement
39
+ requirement: &79360360 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ~>
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: 1.0.0
45
45
  type: :runtime
46
46
  prerelease: false
47
- version_requirements: *78504740
47
+ version_requirements: *79360360
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: hash-keys
50
- requirement: &78504280 !ruby/object:Gem::Requirement
50
+ requirement: &79359860 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ~>
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: 1.0.0
56
56
  type: :runtime
57
57
  prerelease: false
58
- version_requirements: *78504280
58
+ version_requirements: *79359860
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: hollywood
61
- requirement: &78503980 !ruby/object:Gem::Requirement
61
+ requirement: &79359520 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ~>
@@ -66,10 +66,10 @@ dependencies:
66
66
  version: 1.0.0
67
67
  type: :runtime
68
68
  prerelease: false
69
- version_requirements: *78503980
69
+ version_requirements: *79359520
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: require_all
72
- requirement: &78503200 !ruby/object:Gem::Requirement
72
+ requirement: &79359140 !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
75
  - - ~>
@@ -77,10 +77,10 @@ dependencies:
77
77
  version: 1.2.0
78
78
  type: :runtime
79
79
  prerelease: false
80
- version_requirements: *78503200
80
+ version_requirements: *79359140
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: robustthread
83
- requirement: &78502800 !ruby/object:Gem::Requirement
83
+ requirement: &79358710 !ruby/object:Gem::Requirement
84
84
  none: false
85
85
  requirements:
86
86
  - - ~>
@@ -88,10 +88,10 @@ dependencies:
88
88
  version: 0.5.2
89
89
  type: :runtime
90
90
  prerelease: false
91
- version_requirements: *78502800
91
+ version_requirements: *79358710
92
92
  - !ruby/object:Gem::Dependency
93
93
  name: safely
94
- requirement: &78502520 !ruby/object:Gem::Requirement
94
+ requirement: &79358290 !ruby/object:Gem::Requirement
95
95
  none: false
96
96
  requirements:
97
97
  - - ~>
@@ -99,10 +99,10 @@ dependencies:
99
99
  version: 0.3.0
100
100
  type: :runtime
101
101
  prerelease: false
102
- version_requirements: *78502520
102
+ version_requirements: *79358290
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: amqp
105
- requirement: &78502200 !ruby/object:Gem::Requirement
105
+ requirement: &79357840 !ruby/object:Gem::Requirement
106
106
  none: false
107
107
  requirements:
108
108
  - - ~>
@@ -110,10 +110,10 @@ dependencies:
110
110
  version: 0.8.0
111
111
  type: :runtime
112
112
  prerelease: false
113
- version_requirements: *78502200
113
+ version_requirements: *79357840
114
114
  - !ruby/object:Gem::Dependency
115
115
  name: bson_ext
116
- requirement: &78490410 !ruby/object:Gem::Requirement
116
+ requirement: &79357520 !ruby/object:Gem::Requirement
117
117
  none: false
118
118
  requirements:
119
119
  - - ~>
@@ -121,10 +121,10 @@ dependencies:
121
121
  version: 1.3.1
122
122
  type: :runtime
123
123
  prerelease: false
124
- version_requirements: *78490410
124
+ version_requirements: *79357520
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: eventmachine
127
- requirement: &78490140 !ruby/object:Gem::Requirement
127
+ requirement: &79357270 !ruby/object:Gem::Requirement
128
128
  none: false
129
129
  requirements:
130
130
  - - ~>
@@ -132,10 +132,10 @@ dependencies:
132
132
  version: 0.12.10
133
133
  type: :runtime
134
134
  prerelease: false
135
- version_requirements: *78490140
135
+ version_requirements: *79357270
136
136
  - !ruby/object:Gem::Dependency
137
137
  name: mongo
138
- requirement: &78489850 !ruby/object:Gem::Requirement
138
+ requirement: &79356960 !ruby/object:Gem::Requirement
139
139
  none: false
140
140
  requirements:
141
141
  - - ~>
@@ -143,10 +143,10 @@ dependencies:
143
143
  version: 1.3.1
144
144
  type: :runtime
145
145
  prerelease: false
146
- version_requirements: *78489850
146
+ version_requirements: *79356960
147
147
  - !ruby/object:Gem::Dependency
148
148
  name: evented-spec
149
- requirement: &78489210 !ruby/object:Gem::Requirement
149
+ requirement: &79356660 !ruby/object:Gem::Requirement
150
150
  none: false
151
151
  requirements:
152
152
  - - ~>
@@ -154,10 +154,10 @@ dependencies:
154
154
  version: 0.9.0
155
155
  type: :development
156
156
  prerelease: false
157
- version_requirements: *78489210
157
+ version_requirements: *79356660
158
158
  - !ruby/object:Gem::Dependency
159
159
  name: awesome_print
160
- requirement: &78488670 !ruby/object:Gem::Requirement
160
+ requirement: &79356350 !ruby/object:Gem::Requirement
161
161
  none: false
162
162
  requirements:
163
163
  - - ~>
@@ -165,10 +165,10 @@ dependencies:
165
165
  version: 0.4.0
166
166
  type: :development
167
167
  prerelease: false
168
- version_requirements: *78488670
168
+ version_requirements: *79356350
169
169
  - !ruby/object:Gem::Dependency
170
170
  name: faker
171
- requirement: &78487990 !ruby/object:Gem::Requirement
171
+ requirement: &79355980 !ruby/object:Gem::Requirement
172
172
  none: false
173
173
  requirements:
174
174
  - - ~>
@@ -176,10 +176,10 @@ dependencies:
176
176
  version: 1.0.0
177
177
  type: :development
178
178
  prerelease: false
179
- version_requirements: *78487990
179
+ version_requirements: *79355980
180
180
  - !ruby/object:Gem::Dependency
181
181
  name: fuubar
182
- requirement: &78487720 !ruby/object:Gem::Requirement
182
+ requirement: &79355660 !ruby/object:Gem::Requirement
183
183
  none: false
184
184
  requirements:
185
185
  - - ~>
@@ -187,10 +187,10 @@ dependencies:
187
187
  version: 0.0.0
188
188
  type: :development
189
189
  prerelease: false
190
- version_requirements: *78487720
190
+ version_requirements: *79355660
191
191
  - !ruby/object:Gem::Dependency
192
192
  name: rspec
193
- requirement: &78487480 !ruby/object:Gem::Requirement
193
+ requirement: &79355170 !ruby/object:Gem::Requirement
194
194
  none: false
195
195
  requirements:
196
196
  - - ~>
@@ -198,7 +198,7 @@ dependencies:
198
198
  version: 2.6.0
199
199
  type: :development
200
200
  prerelease: false
201
- version_requirements: *78487480
201
+ version_requirements: *79355170
202
202
  description: JRuby RabbitMq bindings
203
203
  email:
204
204
  - lee.m.henson@gmail.com
@@ -208,20 +208,19 @@ extensions: []
208
208
  extra_rdoc_files: []
209
209
  files:
210
210
  - Gemfile
211
- - Gemfile.lock
212
211
  - Rakefile
213
212
  - euston-rabbitmq.gemspec
214
213
  - lib/euston-rabbitmq.rb
215
- - lib/euston-rabbitmq/buffered_message_dispatcher.rb
216
- - lib/euston-rabbitmq/command_handler_bindings.rb
214
+ - lib/euston-rabbitmq/bindings/command_handler_binder.rb
215
+ - lib/euston-rabbitmq/bindings/event_handler_binder.rb
216
+ - lib/euston-rabbitmq/bindings/handler_binder.rb
217
217
  - lib/euston-rabbitmq/command_handlers/retry_failed_message.rb
218
+ - lib/euston-rabbitmq/constant_loader.rb
218
219
  - lib/euston-rabbitmq/errors.rb
219
- - lib/euston-rabbitmq/event_handler_binding.rb
220
- - lib/euston-rabbitmq/event_handler_bindings.rb
221
220
  - lib/euston-rabbitmq/event_handlers/message_failure.rb
222
- - lib/euston-rabbitmq/event_store_dispatcher.rb
223
221
  - lib/euston-rabbitmq/exchanges.rb
224
- - lib/euston-rabbitmq/handler_bindings.rb
222
+ - lib/euston-rabbitmq/handler_finder.rb
223
+ - lib/euston-rabbitmq/handler_reference.rb
225
224
  - lib/euston-rabbitmq/message_buffer.rb
226
225
  - lib/euston-rabbitmq/message_logger.rb
227
226
  - lib/euston-rabbitmq/queue.rb
@@ -229,10 +228,13 @@ files:
229
228
  - lib/euston-rabbitmq/read_model/failed_message.rb
230
229
  - lib/euston-rabbitmq/read_model/message_buffer.rb
231
230
  - lib/euston-rabbitmq/read_model/message_log.rb
231
+ - lib/euston-rabbitmq/subscriptions/retriable_subscription.rb
232
232
  - lib/euston-rabbitmq/version.rb
233
233
  - spec/command_buffer_spec.rb
234
+ - spec/constant_loader_spec.rb
234
235
  - spec/event_buffer_spec.rb
235
236
  - spec/exchange_declaration_spec.rb
237
+ - spec/handler_finder_spec.rb
236
238
  - spec/message_failure_spec.rb
237
239
  - spec/mt_safe_queue_subscription_spec.rb
238
240
  - spec/safe_queue_subscription_spec.rb
data/Gemfile.lock DELETED
@@ -1,103 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- euston-rabbitmq (1.0.0)
5
- activesupport (~> 3.0.0)
6
- amqp (~> 0.8.0)
7
- bson_ext (~> 1.3.1)
8
- euston (~> 1.0.0)
9
- euston-eventstore (~> 1.0.0)
10
- eventmachine (~> 0.12.10)
11
- hash-keys (~> 1.0.0)
12
- hollywood (~> 1.0.0)
13
- mongo (~> 1.3.1)
14
- require_all (~> 1.2.0)
15
- robustthread (~> 0.5.2)
16
- safely (~> 0.3.0)
17
-
18
- GEM
19
- remote: http://rubygems.org/
20
- specs:
21
- activesupport (3.0.10)
22
- amq-client (0.8.3)
23
- amq-protocol (>= 0.8.0)
24
- eventmachine
25
- amq-protocol (0.8.1)
26
- amqp (0.8.0)
27
- amq-client (~> 0.8.3)
28
- amq-protocol (~> 0.8.0)
29
- eventmachine
30
- awesome_print (0.4.0)
31
- bson (1.3.1)
32
- bson (1.3.1-java)
33
- bson_ext (1.3.1)
34
- diff-lcs (1.1.3)
35
- euston (1.0.0)
36
- activesupport (~> 3.0.9)
37
- euston-eventstore (~> 1.0.0)
38
- require_all (~> 1.2.0)
39
- euston-eventstore (1.0.4)
40
- activesupport (~> 3.0.9)
41
- bson_ext (~> 1.3.1)
42
- hash-keys (~> 1.0.0)
43
- json (~> 1.5.0)
44
- mongo (~> 1.3.1)
45
- require_all (~> 1.2.0)
46
- uuid (~> 2.3.0)
47
- euston-eventstore (1.0.4-java)
48
- activesupport (~> 3.0.9)
49
- hash-keys (~> 1.0.0)
50
- jmongo (~> 1.0.0)
51
- json-jruby (~> 1.5.0)
52
- require_all (~> 1.2.0)
53
- uuid (~> 2.3.0)
54
- evented-spec (0.9.0)
55
- eventmachine (0.12.10)
56
- eventmachine (0.12.10-java)
57
- faker (1.0.0)
58
- i18n (~> 0.4)
59
- fuubar (0.0.6)
60
- rspec (~> 2.0)
61
- rspec-instafail (~> 0.1.8)
62
- ruby-progressbar (~> 0.0.10)
63
- hash-keys (1.0.0)
64
- hollywood (1.0.0)
65
- i18n (0.6.0)
66
- jmongo (1.0.3)
67
- require_all (~> 1.2)
68
- json (1.5.0)
69
- json (1.5.0-java)
70
- json-jruby (1.5.0-java)
71
- json (= 1.5.0)
72
- macaddr (1.4.0)
73
- systemu (~> 2.2.0)
74
- mongo (1.3.1)
75
- bson (>= 1.3.1)
76
- require_all (1.2.0)
77
- robustthread (0.5.2)
78
- rspec (2.6.0)
79
- rspec-core (~> 2.6.0)
80
- rspec-expectations (~> 2.6.0)
81
- rspec-mocks (~> 2.6.0)
82
- rspec-core (2.6.4)
83
- rspec-expectations (2.6.0)
84
- diff-lcs (~> 1.1.2)
85
- rspec-instafail (0.1.8)
86
- rspec-mocks (2.6.0)
87
- ruby-progressbar (0.0.10)
88
- safely (0.3.0)
89
- systemu (2.2.0)
90
- uuid (2.3.4)
91
- macaddr (~> 1.0)
92
-
93
- PLATFORMS
94
- java
95
- ruby
96
-
97
- DEPENDENCIES
98
- awesome_print (~> 0.4.0)
99
- euston-rabbitmq!
100
- evented-spec (~> 0.9.0)
101
- faker (~> 1.0.0)
102
- fuubar (~> 0.0.0)
103
- rspec (~> 2.6.0)
@@ -1,48 +0,0 @@
1
- module Euston
2
- module RabbitMq
3
- class BufferedMessageDispatcher
4
- class << self
5
- def command_dispatcher channel
6
- @command_dispatcher ||= BufferedMessageDispatcher.new(Euston::RabbitMq::MessageBuffer.commands_buffer channel)
7
- end
8
-
9
- def event_dispatcher channel
10
- @event_dispatcher ||= BufferedMessageDispatcher.new(Euston::RabbitMq::MessageBuffer.events_buffer channel)
11
- end
12
- end
13
-
14
- include Euston::RabbitMq::Exchanges
15
-
16
- def initialize buffer
17
- @buffer = buffer
18
- @buffer.when(:no_messages_were_due) { @sleep = true }
19
- end
20
-
21
- attr_writer :wait_time
22
-
23
- def wait_time
24
- @wait_time ||= 1
25
- end
26
-
27
- def stop
28
- @stop = true
29
- end
30
-
31
- def start
32
- @stop = false
33
-
34
- dispatch_loop = Proc.new do
35
- @sleep = false
36
-
37
- begin
38
- @buffer.dispatch_due_messages
39
- end while !@sleep
40
-
41
- EM.add_timer(wait_time) { dispatch_loop.call } unless @stop
42
- end
43
-
44
- EM.add_timer(wait_time) { dispatch_loop.call }
45
- end
46
- end
47
- end
48
- end
@@ -1,30 +0,0 @@
1
- module Euston
2
- module RabbitMq
3
- class CommandHandlerBindings < HandlerBindings
4
- def finalize_bindings
5
- super
6
- attach_queue_hook_listeners queue
7
- end
8
-
9
- protected
10
-
11
- def bind_handler handler_type
12
- queue.bind @exchanges[:commands], :routing_key => "commands.#{handler_type.to_s.underscore}"
13
- end
14
-
15
- def call_handler message
16
- command_headers = CommandHeaders.from_hash(message[:headers]).freeze
17
- command_body = message[:body].freeze
18
- handler_type = command_headers.type.to_s.camelize.to_sym
19
- find_namespaces_containing_handler_type(handler_type).each do |namespace|
20
- handler = namespace.const_get handler_type
21
- handler.new.send "__version__#{command_headers.version}", command_headers, command_body
22
- end
23
- end
24
-
25
- def queue
26
- @queue ||= get_queue @channel, :command_handlers
27
- end
28
- end
29
- end
30
- end
@@ -1,114 +0,0 @@
1
- module Euston
2
- module RabbitMq
3
- class EventHandlerBinding
4
- include Euston::RabbitMq::Queues
5
- include Euston::RabbitMq::Exchanges
6
-
7
- PREFIX = '__event_handler__'
8
-
9
- def initialize(channel, namespace, handler_type)
10
- @channel, @namespace, @handler_type = channel, namespace, handler_type
11
-
12
- name = @handler_type.to_s.underscore
13
- @queue = get_queue(@channel, name)
14
- instance_variable_set "@#{name}".to_sym, @queue
15
- @handler_class = @namespace.const_get @handler_type
16
- @exchange = get_exchange(@channel, :events)
17
- end
18
-
19
- def bind
20
- bindable_methods.each do |method|
21
- @queue.bind @exchange, :routing_key => "events.#{method}"
22
- end
23
- self
24
- end
25
-
26
- def listen
27
- attach_queue_hook_listeners @queue
28
- end
29
-
30
- private
31
-
32
- def attach_queue_hook_listeners queue
33
- queue.when(:message_decode_failed => method(:log_decode_failure),
34
- :message_failed => method(:handle_failure),
35
- :message_received => method(:call_handler))
36
-
37
- queue.safe_subscribe
38
- end
39
-
40
- def call_handler(message)
41
- event_headers = EventHeaders.from_hash message[:headers]
42
- event_body = message[:body]
43
-
44
- @handler_class.new.send "#{PREFIX}#{event_headers.type}__#{event_headers.version}", event_headers.freeze, event_body.freeze
45
- end
46
-
47
- def bindable_methods
48
- methods = @handler_class.public_instance_methods(false)
49
- methods = methods.select { |method| method.to_s.start_with? PREFIX }
50
- methods = methods.map { |method| method.to_s[PREFIX.length, method.to_s.length - PREFIX.length] }
51
- methods = methods.map { |method| method.split('__').first }
52
- methods.uniq
53
- end
54
-
55
- def create_message_failed_message error, failed_message, amqp_header
56
- {
57
- :headers =>
58
- {
59
- :id => Euston.uuid.generate.to_s,
60
- :type => :message_failed,
61
- :version => 1,
62
- :timestamp => Time.now.to_f
63
- },
64
-
65
- :body =>
66
- {
67
- :message => failed_message,
68
- :routing_key => amqp_header.method.routing_key,
69
- :error => error.message,
70
- :backtrace => error.backtrace
71
- }
72
- }
73
- end
74
-
75
- def handle_failure message, error, amqp_header
76
- failures = message[:failures] || 0
77
- failures = failures + 1
78
- message[:failures] = failures
79
-
80
- begin
81
- if failures == 3
82
- message.delete :failures
83
- message = create_message_failed_message error, message, amqp_header
84
-
85
- options = { :key => 'events.message_failed' }
86
- exchange_ref = :events
87
- else
88
- options = { :key => amqp_header.method.routing_key }
89
- exchange_ref = amqp_header.method.routing_key.split('.').first.to_sym
90
- end
91
-
92
- options = default_publish_options.merge options
93
- exchange = get_exchange(@channel, exchange_ref)
94
- message = ::ActiveSupport::JSON.encode message
95
-
96
- exchange.publish message, options
97
-
98
- amqp_header.ack
99
- rescue StandardError => e
100
- amqp_header.reject :requeue => true
101
- raise e
102
- end
103
- end
104
-
105
- def log_decode_failure message, error
106
- text = "A handler queue subscription failed. [Error] #{error.message} [Payload] #{message}"
107
- err = Euston::RabbitMq::MessageDecodeFailedError.new text
108
- err.set_backtrace error.backtrace
109
-
110
- Safely.report! err
111
- end
112
- end
113
- end
114
- end
@@ -1,30 +0,0 @@
1
- module Euston
2
- module RabbitMq
3
- class EventHandlerBindings < HandlerBindings
4
- PREFIX = '__event_handler__'
5
-
6
- protected
7
-
8
- def bind_handler handler_type
9
- name = handler_type.to_s.underscore
10
- queue = get_queue @channel, name
11
- instance_variable_set "@#{name}".to_sym, queue
12
-
13
- namespace = find_namespaces_containing_handler_type(handler_type).first
14
- handler_class = namespace.const_get handler_type
15
- methods = handler_class.public_instance_methods(false)
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 }
19
- methods.uniq.each { |method| queue.bind @exchanges[:events], :routing_key => "events.#{method}" }
20
-
21
- attach_queue_hook_listeners queue do |message|
22
- event_headers = EventHeaders.from_hash message[:headers]
23
- event_body = message[:body]
24
-
25
- handler_class.new.send "#{PREFIX}#{event_headers.type}__#{event_headers.version}", event_headers.freeze, event_body.freeze
26
- end
27
- end
28
- end
29
- end
30
- end
@@ -1,45 +0,0 @@
1
- module Euston
2
- module RabbitMq
3
- class EventStoreDispatcher
4
- def initialize channel
5
- @channel = channel
6
- @event_buffer = Euston::RabbitMq::MessageBuffer.events_buffer channel
7
- @event_store = Euston::RabbitMq.event_store
8
- end
9
-
10
- attr_writer :wait_time
11
-
12
- def wait_time
13
- @wait_time ||= 1
14
- end
15
-
16
- def stop
17
- @stop = true
18
- end
19
-
20
- def start
21
- @stop = false
22
-
23
- dispatch_loop = Proc.new do
24
- begin
25
- begin
26
- commits = @event_store.get_undispatched_commits
27
-
28
- commits.each do |commit|
29
- commit.events.each { |event| @event_buffer.push event.to_hash }
30
-
31
- @event_store.mark_commit_as_dispatched commit
32
- end
33
- end while !commits.empty?
34
- rescue StandardError => e
35
- DaemonKit::logger.error "#{e}\n#{e.backtrace}"
36
- end
37
-
38
- EM.add_timer(wait_time) { dispatch_loop.call } unless @stop
39
- end
40
-
41
- EM.add_timer(wait_time) { dispatch_loop.call }
42
- end
43
- end
44
- end
45
- end