euston-rabbitmq 1.0.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.
Files changed (32) hide show
  1. data/Gemfile +2 -0
  2. data/Gemfile.lock +103 -0
  3. data/Rakefile +182 -0
  4. data/euston-rabbitmq.gemspec +74 -0
  5. data/lib/euston-rabbitmq/buffered_message_dispatcher.rb +48 -0
  6. data/lib/euston-rabbitmq/command_handler_bindings.rb +30 -0
  7. data/lib/euston-rabbitmq/command_handlers/retry_failed_message.rb +29 -0
  8. data/lib/euston-rabbitmq/errors.rb +5 -0
  9. data/lib/euston-rabbitmq/event_handler_binding.rb +114 -0
  10. data/lib/euston-rabbitmq/event_handler_bindings.rb +30 -0
  11. data/lib/euston-rabbitmq/event_handlers/message_failure.rb +27 -0
  12. data/lib/euston-rabbitmq/event_store_dispatcher.rb +45 -0
  13. data/lib/euston-rabbitmq/exchanges.rb +17 -0
  14. data/lib/euston-rabbitmq/handler_bindings.rb +115 -0
  15. data/lib/euston-rabbitmq/message_buffer.rb +68 -0
  16. data/lib/euston-rabbitmq/message_logger.rb +50 -0
  17. data/lib/euston-rabbitmq/queue.rb +30 -0
  18. data/lib/euston-rabbitmq/queues.rb +13 -0
  19. data/lib/euston-rabbitmq/read_model/failed_message.rb +36 -0
  20. data/lib/euston-rabbitmq/read_model/message_buffer.rb +52 -0
  21. data/lib/euston-rabbitmq/read_model/message_log.rb +37 -0
  22. data/lib/euston-rabbitmq/version.rb +5 -0
  23. data/lib/euston-rabbitmq.rb +28 -0
  24. data/spec/command_buffer_spec.rb +69 -0
  25. data/spec/event_buffer_spec.rb +69 -0
  26. data/spec/exchange_declaration_spec.rb +28 -0
  27. data/spec/message_failure_spec.rb +77 -0
  28. data/spec/mt_safe_queue_subscription_spec.rb +72 -0
  29. data/spec/safe_queue_subscription_spec.rb +50 -0
  30. data/spec/spec_helper.rb +65 -0
  31. data/spec/support/factories.rb +18 -0
  32. metadata +233 -0
@@ -0,0 +1,77 @@
1
+ require File.expand_path('../spec_helper.rb', __FILE__)
2
+
3
+ unless RUBY_PLATFORM == 'java'
4
+ module MessageFailureTracking
5
+ module FailingCommandHandlers
6
+ class DeliverWidget
7
+ class << self
8
+ attr_accessor :fail_next
9
+ end
10
+
11
+ include Euston::CommandHandler
12
+
13
+ version 1 do |headers, command|
14
+ if self.class.fail_next
15
+ raise 'User-generated failure'
16
+ else
17
+ publish headers, command
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ describe 'message failure tracking' do
25
+ include EustonRmqSpec
26
+ include Euston::RabbitMq::Exchanges
27
+ include Euston::RabbitMq::Queues
28
+
29
+ amqp_before do
30
+ @exchange = get_exchange @channel, :commands
31
+ @handler = ::MessageFailureTracking::FailingCommandHandlers::DeliverWidget
32
+
33
+ command_handlers = Euston::RabbitMq::CommandHandlerBindings.new @channel
34
+ command_handlers.add_namespace Euston::RabbitMq::CommandHandlers
35
+ command_handlers.add_namespace ::MessageFailureTracking::FailingCommandHandlers
36
+ command_handlers.finalize_bindings
37
+
38
+ event_handlers = Euston::RabbitMq::EventHandlerBindings.new @channel
39
+ event_handlers.add_namespace Euston::RabbitMq::EventHandlers
40
+ event_handlers.finalize_bindings
41
+
42
+ @command = { :headers => { :id => Euston.uuid.generate,
43
+ :type => 'deliver_widget',
44
+ :version => 1 },
45
+ :body => { :id => Euston.uuid.generate,
46
+ :name => 'Bill Smith' } }
47
+ end
48
+
49
+ def publish
50
+ json = ::ActiveSupport::JSON.encode(@command)
51
+ opts = default_publish_options.merge(:routing_key => 'commands.deliver_widget')
52
+ delayed(0.3) { @exchange.publish json, opts }
53
+ end
54
+
55
+ context 'a failing command is published' do
56
+ it 'moves the message to the failed-messages queue' do
57
+ @handler.fail_next = true
58
+ received = 0
59
+
60
+ delayed(0.3) {
61
+ @queue = get_queue @channel, :message_failure
62
+ @queue.when(:message_received => ->(message) { received = received + 1 })
63
+
64
+ publish
65
+ }
66
+
67
+ done(3) {
68
+ received.should == 1
69
+ }
70
+ end
71
+ end
72
+
73
+ context 'a failed message is retried' do
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,72 @@
1
+ require File.expand_path('../spec_helper.rb', __FILE__)
2
+
3
+ if RUBY_PLATFORM == 'java'
4
+ require 'spec_helper'
5
+
6
+ describe 'message-failure-aware queue subscription' do
7
+ include EustonRmqSpec
8
+
9
+ PUBLISH_OPTS = { :immediate => false,
10
+ :mandatory => true,
11
+ :persistent => true,
12
+ :routing_key => 'messages.xyz' }
13
+
14
+ before :each do
15
+ @queue = @exchange = nil
16
+ @exchange = @channel.topic "test-#{Euston.uuid.generate}", :durable => true, :nowait => false
17
+ @queue = @channel.queue "test-#{Euston.uuid.generate}", :durable => true, :nowait => false
18
+
19
+ @queue.bind @exchange, :routing_key => 'messages.#'
20
+ @th = Thread.new do
21
+ Thread.current[:failed_count] = 0
22
+ Thread.current[:succeed_count] = 0
23
+
24
+ def on_message_decode_failed(message, error)
25
+ Thread.current[:failed_count] += 1
26
+ end
27
+
28
+ def on_message_failed(message, error, msg)
29
+ Thread.current[:failed_count] += 1
30
+ end
31
+
32
+ def on_message_received(message)
33
+ if message[:a] == 'oops'
34
+ raise 'Something bad happened'
35
+ else
36
+ Thread.current[:succeed_count] += 1
37
+ end
38
+ end
39
+
40
+ @queue.when(:message_decode_failed => method(:on_message_decode_failed),
41
+ :message_failed => method(:on_message_failed),
42
+ :message_received => method(:on_message_received))
43
+
44
+ @queue.safe_subscribe
45
+ end
46
+
47
+ @th.abort_on_exception = true
48
+ end
49
+
50
+ after :each do
51
+ @th.kill
52
+ end
53
+
54
+ it 'adds a failure-aware subscription function to the amqp queue object' do
55
+ @queue.class.should == AMQP::Queue
56
+ @queue.should respond_to(:safe_subscribe)
57
+
58
+ @exchange.publish ' *897d- -', PUBLISH_OPTS
59
+ sleep 0.25
60
+ @th[:failed_count].should == 1
61
+
62
+ jsn = JSON.generate({ :a => :b })
63
+ @exchange.publish jsn, PUBLISH_OPTS
64
+ sleep 0.25
65
+ @th[:succeed_count].should == 1
66
+
67
+ @exchange.publish JSON.generate({ :a => 'oops' }), PUBLISH_OPTS
68
+ sleep 0.25
69
+ @th[:failed_count].should == 2
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,50 @@
1
+ require File.expand_path('../spec_helper.rb', __FILE__)
2
+
3
+ unless RUBY_PLATFORM == 'java'
4
+ describe 'message-failure-aware queue subscription' do
5
+ include EustonRmqSpec
6
+
7
+ PUBLISH_OPTS = { :immediate => false,
8
+ :mandatory => true,
9
+ :persistent => true,
10
+ :routing_key => 'messages.xyz' }
11
+
12
+ amqp_before do
13
+ @exchange = @channel.topic "test-#{Euston.uuid.generate}", :durable => true, :nowait => false
14
+ @queue = @channel.queue "test-#{Euston.uuid.generate}", :durable => true, :nowait => false
15
+ @queue.bind @exchange, :routing_key => 'messages.#'
16
+ @queue.safe_subscribe
17
+ end
18
+
19
+ it 'adds a failure-aware subscription function to the amqp queue object' do
20
+ @queue.should respond_to(:safe_subscribe)
21
+
22
+ done 1
23
+ end
24
+
25
+ it 'publishes the message-decode-failed event when a non-json message is received by the queue' do
26
+ count = 0
27
+ @queue.when :message_decode_failed => ->(message, error) { count = count + 1 }
28
+
29
+ delayed(0.3) { @exchange.publish ' *897d- -', PUBLISH_OPTS }
30
+ done(1) { count.should == 1 }
31
+ end
32
+
33
+ it 'publishes the message-received event when a message is received by the queue' do
34
+ count = 0
35
+ @queue.when :message_received => ->(message) { count = count + 1 }
36
+
37
+ delayed(0.3) { @exchange.publish ::ActiveSupport::JSON.encode({ :a => :b }), PUBLISH_OPTS }
38
+ done(1) { count.should == 1 }
39
+ end
40
+
41
+ it 'publishes the message-failed event when an exception occurs during the message-received handler' do
42
+ count = 0
43
+ @queue.when(:message_failed => ->(message, error, header) { count = count + 1 },
44
+ :message_received => ->(message) { raise 'Something bad happened' })
45
+
46
+ delayed(0.3) { @exchange.publish ::ActiveSupport::JSON.encode({ :a => :b }), PUBLISH_OPTS }
47
+ done(1) { count.should == 1 }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,65 @@
1
+ AMQP_OPTS = { :user => 'euston-rabbitmq-tester',
2
+ :pass => 'password',
3
+ :host => 'localhost',
4
+ :vhost => '/euston-rabbitmq-test' }
5
+
6
+ require 'ap'
7
+ require 'euston-rabbitmq'
8
+ require 'evented-spec' unless RUBY_PLATFORM == 'java'
9
+ require 'faker'
10
+ require_rel 'support'
11
+
12
+ def trim_array_ends array
13
+ array.shift
14
+ array.pop
15
+ array
16
+ end
17
+
18
+ module EustonRmqSpec
19
+ def self.included scope
20
+ unless RUBY_PLATFORM == 'java'
21
+ scope.send :include, EventedSpec::AMQPSpec
22
+ scope.send :default_options, AMQP_OPTS
23
+ scope.send :default_timeout, 60
24
+ end
25
+
26
+ scope.send :before, :each do
27
+ vhosts = `rabbitmqctl list_vhosts`.split("\n")
28
+ vhosts = trim_array_ends vhosts
29
+ vhost = '/euston-rabbitmq-test'
30
+
31
+ `rabbitmqctl delete_vhost #{vhost}` if vhosts.include? vhost
32
+ `rabbitmqctl add_vhost #{vhost}`
33
+
34
+ users = `rabbitmqctl list_users`.split("\n")
35
+ users = trim_array_ends users
36
+ users = users.map { |u| u.split("\t").shift }
37
+
38
+ user, password = 'euston-rabbitmq-tester', 'password'
39
+
40
+ `rabbitmqctl delete_user #{user}` if users.include? user
41
+ `rabbitmqctl add_user #{user} #{password}`
42
+ `rabbitmqctl set_permissions -p #{vhost} #{user} ".*" ".*" ".*"`
43
+ `rabbitmqctl set_permissions -p #{vhost} guest ".*" ".*" ".*"` if users.include? 'guest'
44
+ end
45
+
46
+ scope.send :before, :each do
47
+ connection = Mongo::Connection.new('localhost', 27017)
48
+ db = connection.db('euston-rabbitmq-test-event-store')
49
+ db.collections.select { |c| c.name !~ /system/ }.each { |c| db.drop_collection c.name }
50
+ Euston::RabbitMq.event_store_mongodb = db
51
+ end
52
+
53
+ if RUBY_PLATFORM == 'java'
54
+ scope.send :before, :each do
55
+ AMQP.settings.merge! AMQP_OPTS
56
+ @channel = AMQP::Channel.new
57
+ end
58
+ else
59
+ scope.send :amqp_before do
60
+ @channel = AMQP::Channel.new
61
+ @channel.should be_open
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,18 @@
1
+ module Factory
2
+ class << self
3
+ def command_headers
4
+ {
5
+ :id => Euston.uuid.generate,
6
+ :type => Faker::Lorem.words(2).join('_'),
7
+ :version => 1
8
+ }
9
+ end
10
+
11
+ def command
12
+ {
13
+ :headers => Factory.command_headers,
14
+ :body => Hash[Faker::Lorem.words(3).map { |w| [w.downcase.to_sym, Faker::Lorem.words(3).join(' ')] }]
15
+ }
16
+ end
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,233 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: euston-rabbitmq
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 1.0.0
6
+ platform: java
7
+ authors:
8
+ - Lee Henson
9
+ - Guy Boertje
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2011-09-16 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ version_requirements: &2058 !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.0
22
+ none: false
23
+ requirement: *2058
24
+ prerelease: false
25
+ type: :runtime
26
+ - !ruby/object:Gem::Dependency
27
+ name: euston
28
+ version_requirements: &2076 !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
33
+ none: false
34
+ requirement: *2076
35
+ prerelease: false
36
+ type: :runtime
37
+ - !ruby/object:Gem::Dependency
38
+ name: euston-eventstore
39
+ version_requirements: &2092 !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.0
44
+ none: false
45
+ requirement: *2092
46
+ prerelease: false
47
+ type: :runtime
48
+ - !ruby/object:Gem::Dependency
49
+ name: hash-keys
50
+ version_requirements: &2108 !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.0
55
+ none: false
56
+ requirement: *2108
57
+ prerelease: false
58
+ type: :runtime
59
+ - !ruby/object:Gem::Dependency
60
+ name: hollywood
61
+ version_requirements: &2124 !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 1.0.0
66
+ none: false
67
+ requirement: *2124
68
+ prerelease: false
69
+ type: :runtime
70
+ - !ruby/object:Gem::Dependency
71
+ name: require_all
72
+ version_requirements: &2140 !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 1.2.0
77
+ none: false
78
+ requirement: *2140
79
+ prerelease: false
80
+ type: :runtime
81
+ - !ruby/object:Gem::Dependency
82
+ name: robustthread
83
+ version_requirements: &2156 !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ version: 0.5.2
88
+ none: false
89
+ requirement: *2156
90
+ prerelease: false
91
+ type: :runtime
92
+ - !ruby/object:Gem::Dependency
93
+ name: safely
94
+ version_requirements: &2172 !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ~>
97
+ - !ruby/object:Gem::Version
98
+ version: 0.3.0
99
+ none: false
100
+ requirement: *2172
101
+ prerelease: false
102
+ type: :runtime
103
+ - !ruby/object:Gem::Dependency
104
+ name: jmongo
105
+ version_requirements: &2188 !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 1.0.0
110
+ none: false
111
+ requirement: *2188
112
+ prerelease: false
113
+ type: :runtime
114
+ - !ruby/object:Gem::Dependency
115
+ name: jessica
116
+ version_requirements: &2204 !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ~>
119
+ - !ruby/object:Gem::Version
120
+ version: 1.0.0
121
+ none: false
122
+ requirement: *2204
123
+ prerelease: false
124
+ type: :runtime
125
+ - !ruby/object:Gem::Dependency
126
+ name: awesome_print
127
+ version_requirements: &2220 !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: 0.4.0
132
+ none: false
133
+ requirement: *2220
134
+ prerelease: false
135
+ type: :development
136
+ - !ruby/object:Gem::Dependency
137
+ name: faker
138
+ version_requirements: &2238 !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ~>
141
+ - !ruby/object:Gem::Version
142
+ version: 1.0.0
143
+ none: false
144
+ requirement: *2238
145
+ prerelease: false
146
+ type: :development
147
+ - !ruby/object:Gem::Dependency
148
+ name: fuubar
149
+ version_requirements: &2254 !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ~>
152
+ - !ruby/object:Gem::Version
153
+ version: 0.0.0
154
+ none: false
155
+ requirement: *2254
156
+ prerelease: false
157
+ type: :development
158
+ - !ruby/object:Gem::Dependency
159
+ name: rspec
160
+ version_requirements: &2270 !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ~>
163
+ - !ruby/object:Gem::Version
164
+ version: 2.6.0
165
+ none: false
166
+ requirement: *2270
167
+ prerelease: false
168
+ type: :development
169
+ description: JRuby RabbitMq bindings
170
+ email:
171
+ - lee.m.henson@gmail.com
172
+ - guyboertje@gmail.com
173
+ executables: []
174
+ extensions: []
175
+ extra_rdoc_files: []
176
+ files:
177
+ - Gemfile
178
+ - Gemfile.lock
179
+ - Rakefile
180
+ - euston-rabbitmq.gemspec
181
+ - lib/euston-rabbitmq.rb
182
+ - lib/euston-rabbitmq/buffered_message_dispatcher.rb
183
+ - lib/euston-rabbitmq/command_handler_bindings.rb
184
+ - lib/euston-rabbitmq/command_handlers/retry_failed_message.rb
185
+ - lib/euston-rabbitmq/errors.rb
186
+ - lib/euston-rabbitmq/event_handler_binding.rb
187
+ - lib/euston-rabbitmq/event_handler_bindings.rb
188
+ - lib/euston-rabbitmq/event_handlers/message_failure.rb
189
+ - lib/euston-rabbitmq/event_store_dispatcher.rb
190
+ - lib/euston-rabbitmq/exchanges.rb
191
+ - lib/euston-rabbitmq/handler_bindings.rb
192
+ - lib/euston-rabbitmq/message_buffer.rb
193
+ - lib/euston-rabbitmq/message_logger.rb
194
+ - lib/euston-rabbitmq/queue.rb
195
+ - lib/euston-rabbitmq/queues.rb
196
+ - lib/euston-rabbitmq/read_model/failed_message.rb
197
+ - lib/euston-rabbitmq/read_model/message_buffer.rb
198
+ - lib/euston-rabbitmq/read_model/message_log.rb
199
+ - lib/euston-rabbitmq/version.rb
200
+ - spec/command_buffer_spec.rb
201
+ - spec/event_buffer_spec.rb
202
+ - spec/exchange_declaration_spec.rb
203
+ - spec/message_failure_spec.rb
204
+ - spec/mt_safe_queue_subscription_spec.rb
205
+ - spec/safe_queue_subscription_spec.rb
206
+ - spec/spec_helper.rb
207
+ - spec/support/factories.rb
208
+ homepage: http://github.com/leemhenson/euston-rabbitmq
209
+ licenses: []
210
+ post_install_message:
211
+ rdoc_options: []
212
+ require_paths:
213
+ - lib
214
+ required_ruby_version: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - ! '>='
217
+ - !ruby/object:Gem::Version
218
+ version: '0'
219
+ none: false
220
+ required_rubygems_version: !ruby/object:Gem::Requirement
221
+ requirements:
222
+ - - ! '>='
223
+ - !ruby/object:Gem::Version
224
+ version: '0'
225
+ none: false
226
+ requirements: []
227
+ rubyforge_project:
228
+ rubygems_version: 1.8.9
229
+ signing_key:
230
+ specification_version: 3
231
+ summary: RabbitMq bindings for Euston.
232
+ test_files: []
233
+ ...