euston-rabbitmq 1.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
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
+ ...