rabbit_feed 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/Brewfile +4 -0
- data/DEVELOPING.md +140 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +121 -0
- data/LICENSE.txt +9 -0
- data/README.md +304 -0
- data/Rakefile +30 -0
- data/bin/bundle +3 -0
- data/bin/rabbit_feed +11 -0
- data/example/non_rails_app/.rspec +1 -0
- data/example/non_rails_app/Gemfile +7 -0
- data/example/non_rails_app/Gemfile.lock +56 -0
- data/example/non_rails_app/Rakefile +5 -0
- data/example/non_rails_app/bin/benchmark +63 -0
- data/example/non_rails_app/bin/bundle +3 -0
- data/example/non_rails_app/config/rabbit_feed.yml +8 -0
- data/example/non_rails_app/lib/non_rails_app.rb +32 -0
- data/example/non_rails_app/lib/non_rails_app/event_handler.rb +10 -0
- data/example/non_rails_app/log/.keep +0 -0
- data/example/non_rails_app/spec/lib/non_rails_app/event_handler_spec.rb +14 -0
- data/example/non_rails_app/spec/lib/non_rails_app/event_routing_spec.rb +14 -0
- data/example/non_rails_app/spec/spec_helper.rb +31 -0
- data/example/non_rails_app/tmp/pids/.keep +0 -0
- data/example/rails_app/.gitignore +17 -0
- data/example/rails_app/.node-version +1 -0
- data/example/rails_app/.rspec +1 -0
- data/example/rails_app/Gemfile +36 -0
- data/example/rails_app/Gemfile.lock +173 -0
- data/example/rails_app/README.rdoc +28 -0
- data/example/rails_app/Rakefile +6 -0
- data/example/rails_app/app/assets/images/.keep +0 -0
- data/example/rails_app/app/assets/javascripts/application.js +16 -0
- data/example/rails_app/app/assets/javascripts/beavers.js.coffee +3 -0
- data/example/rails_app/app/assets/stylesheets/application.css +15 -0
- data/example/rails_app/app/assets/stylesheets/beavers.css.scss +3 -0
- data/example/rails_app/app/assets/stylesheets/scaffolds.css.scss +69 -0
- data/example/rails_app/app/controllers/application_controller.rb +5 -0
- data/example/rails_app/app/controllers/beavers_controller.rb +81 -0
- data/example/rails_app/app/controllers/concerns/.keep +0 -0
- data/example/rails_app/app/helpers/application_helper.rb +2 -0
- data/example/rails_app/app/helpers/beavers_helper.rb +2 -0
- data/example/rails_app/app/mailers/.keep +0 -0
- data/example/rails_app/app/models/.keep +0 -0
- data/example/rails_app/app/models/beaver.rb +2 -0
- data/example/rails_app/app/models/concerns/.keep +0 -0
- data/example/rails_app/app/views/beavers/_form.html.erb +21 -0
- data/example/rails_app/app/views/beavers/edit.html.erb +6 -0
- data/example/rails_app/app/views/beavers/index.html.erb +25 -0
- data/example/rails_app/app/views/beavers/index.json.jbuilder +4 -0
- data/example/rails_app/app/views/beavers/new.html.erb +5 -0
- data/example/rails_app/app/views/beavers/show.html.erb +9 -0
- data/example/rails_app/app/views/beavers/show.json.jbuilder +1 -0
- data/example/rails_app/app/views/layouts/application.html.erb +14 -0
- data/example/rails_app/bin/bundle +3 -0
- data/example/rails_app/bin/rails +4 -0
- data/example/rails_app/bin/rake +4 -0
- data/example/rails_app/config.ru +4 -0
- data/example/rails_app/config/application.rb +25 -0
- data/example/rails_app/config/boot.rb +4 -0
- data/example/rails_app/config/database.yml +22 -0
- data/example/rails_app/config/environment.rb +5 -0
- data/example/rails_app/config/environments/development.rb +83 -0
- data/example/rails_app/config/environments/test.rb +39 -0
- data/example/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/example/rails_app/config/initializers/cookies_serializer.rb +3 -0
- data/example/rails_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/example/rails_app/config/initializers/inflections.rb +16 -0
- data/example/rails_app/config/initializers/mime_types.rb +4 -0
- data/example/rails_app/config/initializers/rabbit_feed.rb +43 -0
- data/example/rails_app/config/initializers/session_store.rb +3 -0
- data/example/rails_app/config/initializers/wrap_parameters.rb +14 -0
- data/example/rails_app/config/locales/en.yml +23 -0
- data/example/rails_app/config/rabbit_feed.yml +8 -0
- data/example/rails_app/config/routes.rb +58 -0
- data/example/rails_app/config/secrets.yml +18 -0
- data/example/rails_app/config/unicorn.rb +4 -0
- data/example/rails_app/db/migrate/20140424102400_create_beavers.rb +9 -0
- data/example/rails_app/db/schema.rb +22 -0
- data/example/rails_app/db/seeds.rb +7 -0
- data/example/rails_app/lib/assets/.keep +0 -0
- data/example/rails_app/lib/event_handler.rb +7 -0
- data/example/rails_app/lib/tasks/.keep +0 -0
- data/example/rails_app/log/.keep +0 -0
- data/example/rails_app/public/404.html +67 -0
- data/example/rails_app/public/422.html +67 -0
- data/example/rails_app/public/500.html +66 -0
- data/example/rails_app/public/favicon.ico +0 -0
- data/example/rails_app/public/robots.txt +5 -0
- data/example/rails_app/spec/controllers/beavers_controller_spec.rb +32 -0
- data/example/rails_app/spec/event_routing_spec.rb +15 -0
- data/example/rails_app/spec/spec_helper.rb +51 -0
- data/example/rails_app/test/controllers/.keep +0 -0
- data/example/rails_app/test/controllers/beavers_controller_test.rb +49 -0
- data/example/rails_app/test/fixtures/.keep +0 -0
- data/example/rails_app/test/fixtures/beavers.yml +7 -0
- data/example/rails_app/test/helpers/.keep +0 -0
- data/example/rails_app/test/helpers/beavers_helper_test.rb +4 -0
- data/example/rails_app/test/integration/.keep +0 -0
- data/example/rails_app/test/mailers/.keep +0 -0
- data/example/rails_app/test/models/.keep +0 -0
- data/example/rails_app/test/models/beaver_test.rb +7 -0
- data/example/rails_app/test/test_helper.rb +13 -0
- data/example/rails_app/tmp/pids/.keep +0 -0
- data/example/rails_app/vendor/assets/javascripts/.keep +0 -0
- data/example/rails_app/vendor/assets/stylesheets/.keep +0 -0
- data/lib/dsl.rb +9 -0
- data/lib/rabbit_feed.rb +41 -0
- data/lib/rabbit_feed/client.rb +181 -0
- data/lib/rabbit_feed/configuration.rb +50 -0
- data/lib/rabbit_feed/connection_concern.rb +95 -0
- data/lib/rabbit_feed/consumer.rb +14 -0
- data/lib/rabbit_feed/consumer_connection.rb +108 -0
- data/lib/rabbit_feed/event.rb +43 -0
- data/lib/rabbit_feed/event_definitions.rb +98 -0
- data/lib/rabbit_feed/event_routing.rb +90 -0
- data/lib/rabbit_feed/producer.rb +47 -0
- data/lib/rabbit_feed/producer_connection.rb +65 -0
- data/lib/rabbit_feed/testing_support/rspec_matchers/publish_event.rb +90 -0
- data/lib/rabbit_feed/testing_support/testing_helpers.rb +16 -0
- data/lib/rabbit_feed/version.rb +3 -0
- data/logo.png +0 -0
- data/rabbit_feed.gemspec +35 -0
- data/run_benchmark +35 -0
- data/run_example +62 -0
- data/run_recovery_test +26 -0
- data/spec/features/connectivity.feature +13 -0
- data/spec/features/step_definitions/connectivity_steps.rb +96 -0
- data/spec/fixtures/configuration.yml +14 -0
- data/spec/lib/rabbit_feed/client_spec.rb +116 -0
- data/spec/lib/rabbit_feed/configuration_spec.rb +121 -0
- data/spec/lib/rabbit_feed/connection_concern_spec.rb +116 -0
- data/spec/lib/rabbit_feed/consumer_connection_spec.rb +85 -0
- data/spec/lib/rabbit_feed/event_definitions_spec.rb +139 -0
- data/spec/lib/rabbit_feed/event_routing_spec.rb +121 -0
- data/spec/lib/rabbit_feed/event_spec.rb +33 -0
- data/spec/lib/rabbit_feed/producer_connection_spec.rb +72 -0
- data/spec/lib/rabbit_feed/producer_spec.rb +57 -0
- data/spec/lib/rabbit_feed/testing_support/rspec_matchers/publish_event_spec.rb +60 -0
- data/spec/lib/rabbit_feed/testing_support/testing_helper_spec.rb +34 -0
- data/spec/spec_helper.rb +58 -0
- data/spec/support/shared_examples_for_connections.rb +40 -0
- metadata +305 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
module RabbitFeed
|
2
|
+
module Producer
|
3
|
+
extend self
|
4
|
+
|
5
|
+
attr_accessor :event_definitions
|
6
|
+
|
7
|
+
def publish_event name, payload
|
8
|
+
raise (Error.new 'Unable to publish event. No event definitions set.') unless event_definitions.present?
|
9
|
+
event_definition = event_definitions[name] or raise (Error.new "definition for event: #{name} not found")
|
10
|
+
timestamp = Time.now.utc
|
11
|
+
payload = (enriched_payload payload, event_definition.version, name, timestamp)
|
12
|
+
event = Event.new event_definition.schema, payload
|
13
|
+
ProducerConnection.publish event.serialize, (options name, timestamp)
|
14
|
+
event
|
15
|
+
end
|
16
|
+
|
17
|
+
def stub!
|
18
|
+
ProducerConnection.stub(:publish)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def enriched_payload payload, version, name, timestamp
|
24
|
+
payload.merge ({
|
25
|
+
'application' => RabbitFeed.configuration.application,
|
26
|
+
'host' => Socket.gethostname,
|
27
|
+
'environment' => RabbitFeed.environment,
|
28
|
+
'created_at_utc' => timestamp.iso8601(6),
|
29
|
+
'version' => version,
|
30
|
+
'name' => name,
|
31
|
+
})
|
32
|
+
end
|
33
|
+
|
34
|
+
def routing_key event_name
|
35
|
+
"#{RabbitFeed.environment}.#{RabbitFeed.configuration.application}.#{event_name}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def options event_name, timestamp
|
39
|
+
{
|
40
|
+
routing_key: (routing_key event_name),
|
41
|
+
type: event_name,
|
42
|
+
app_id: RabbitFeed.configuration.application,
|
43
|
+
timestamp: timestamp.to_i,
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module RabbitFeed
|
2
|
+
class ProducerConnection
|
3
|
+
include ConnectionConcern
|
4
|
+
|
5
|
+
PUBLISH_OPTIONS = {
|
6
|
+
persistent: true, # Persist the message to disk
|
7
|
+
mandatory: true, # Return the message if it can't be routed to a queue
|
8
|
+
}.freeze
|
9
|
+
|
10
|
+
EXCHANGE_OPTIONS = {
|
11
|
+
type: :topic, # Allow wildcard routing keys
|
12
|
+
durable: true, # Persist across server restart
|
13
|
+
no_declare: false, # Create the exchange if it does not exist
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
attr_reader :exchange
|
17
|
+
|
18
|
+
def self.handle_returned_message return_info, content
|
19
|
+
RabbitFeed.log.error "Handling returned message on #{self.to_s} details: #{return_info}..."
|
20
|
+
RabbitFeed.exception_notify (ReturnedMessageError.new return_info)
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize channel
|
24
|
+
RabbitFeed.log.debug "Declaring exchange on #{self.to_s} (channel #{channel.id}) named: #{RabbitFeed.configuration.exchange} with options: #{exchange_options}..."
|
25
|
+
@exchange = channel.exchange RabbitFeed.configuration.exchange, exchange_options
|
26
|
+
|
27
|
+
exchange.on_return do |return_info, properties, content|
|
28
|
+
RabbitFeed::ProducerConnection.handle_returned_message return_info, content
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.publish message, options
|
33
|
+
retry_on_closed_connection do
|
34
|
+
with_connection do |producer_connection|
|
35
|
+
retry_on_exception do
|
36
|
+
producer_connection.publish message, options
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def publish message, options
|
43
|
+
# It's critical to dup the options for the sake of retries, as bunny modifies this hash
|
44
|
+
bunny_options = (options.merge PUBLISH_OPTIONS)
|
45
|
+
|
46
|
+
RabbitFeed.log.debug "Publishing message on #{self.to_s} with options: #{options} to exchange: #{RabbitFeed.configuration.exchange}..."
|
47
|
+
|
48
|
+
exchange.publish message, bunny_options
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def exchange_options
|
54
|
+
{
|
55
|
+
auto_delete: RabbitFeed.configuration.auto_delete_exchange,
|
56
|
+
}.merge EXCHANGE_OPTIONS
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.connection_options
|
60
|
+
default_connection_options.merge({
|
61
|
+
threaded: false, # With threading enabled, there is a chance of losing an event during connection recovery
|
62
|
+
})
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module RabbitFeed
|
2
|
+
module TestingSupport
|
3
|
+
module RSpecMatchers
|
4
|
+
class PublishEvent
|
5
|
+
attr_reader :expected_event, :expected_payload, :received_events
|
6
|
+
|
7
|
+
def initialize(expected_event, expected_payload)
|
8
|
+
@expected_event = expected_event
|
9
|
+
@expected_payload = expected_payload
|
10
|
+
@received_events = []
|
11
|
+
stub_publish
|
12
|
+
end
|
13
|
+
|
14
|
+
def matches?(given_proc, negative_expectation = false)
|
15
|
+
unless given_proc.respond_to?(:call)
|
16
|
+
::Kernel.warn "`publish_event` was called with non-proc object #{given_proc.inspect}"
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
given_proc.call
|
22
|
+
rescue
|
23
|
+
end
|
24
|
+
|
25
|
+
actual_event = received_events.detect do |event|
|
26
|
+
event.name == expected_event
|
27
|
+
end
|
28
|
+
|
29
|
+
received_expected_event = actual_event.present?
|
30
|
+
|
31
|
+
with_expected_payload = negative_expectation
|
32
|
+
if received_expected_event && !with_expected_payload
|
33
|
+
actual_payload = (strip_defaults_from actual_event.payload)
|
34
|
+
with_expected_payload = actual_payload == expected_payload
|
35
|
+
end
|
36
|
+
|
37
|
+
return received_expected_event && with_expected_payload
|
38
|
+
end
|
39
|
+
|
40
|
+
alias == matches?
|
41
|
+
|
42
|
+
def does_not_match?(given_proc)
|
43
|
+
!matches?(given_proc, :negative_expectation)
|
44
|
+
end
|
45
|
+
|
46
|
+
def failure_message
|
47
|
+
"expected #{expected_event} with #{expected_payload} but instead received #{received_events_message}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def negative_failure_message
|
51
|
+
"expected no #{expected_event} event, but received one anyways"
|
52
|
+
end
|
53
|
+
|
54
|
+
alias failure_message_when_negated negative_failure_message
|
55
|
+
|
56
|
+
def description
|
57
|
+
"publish_event #{expected_event}"
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def strip_defaults_from payload
|
63
|
+
payload.reject do |key, value|
|
64
|
+
['application', 'host', 'environment', 'created_at_utc', 'version', 'name'].include? key
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def received_events_message
|
69
|
+
if received_events.any?
|
70
|
+
received_events.map do |received_event|
|
71
|
+
"#{received_event.name} with #{strip_defaults_from received_event.payload}"
|
72
|
+
end
|
73
|
+
else
|
74
|
+
'no events'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def stub_publish
|
79
|
+
ProducerConnection.stub(:publish) do |serialized_event, routing_key|
|
80
|
+
@received_events << (Event.deserialize serialized_event)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def publish_event(expected_event, expected_payload)
|
86
|
+
PublishEvent.new(expected_event, expected_payload)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RabbitFeed
|
2
|
+
module TestingSupport
|
3
|
+
module TestingHelpers
|
4
|
+
def rabbit_feed_consumer
|
5
|
+
TestRabbitFeedConsumer.new
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class TestRabbitFeedConsumer
|
10
|
+
def consume_event(event)
|
11
|
+
event = Event.new('no schema',event)
|
12
|
+
RabbitFeed::Consumer.event_routing.handle_event(event)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/logo.png
ADDED
Binary file
|
data/rabbit_feed.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rabbit_feed/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'rabbit_feed'
|
8
|
+
spec.version = RabbitFeed::VERSION
|
9
|
+
spec.authors = ['Simply Business']
|
10
|
+
spec.email = ['tech@simplybusiness.co.uk']
|
11
|
+
spec.description = %q{A gem allowing your application to publish messages to RabbitMQ}
|
12
|
+
spec.summary = %q{This will enable your application to publish messages to a bus to be processed by other services}
|
13
|
+
spec.homepage = 'https://github.com/simplybusiness/rabbit_feed'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
# Gem for interfacing with RabbitMq
|
22
|
+
spec.add_dependency 'bunny'
|
23
|
+
# We use some helpers from ActiveSupport
|
24
|
+
spec.add_dependency 'activesupport'
|
25
|
+
# We use validations from ActiveModel
|
26
|
+
spec.add_dependency 'activemodel'
|
27
|
+
# Provides connection pooling for the producer connections
|
28
|
+
spec.add_dependency 'connection_pool'
|
29
|
+
# Manages process pidfile
|
30
|
+
spec.add_dependency 'pidfile'
|
31
|
+
# Schema definitions and serialization for events
|
32
|
+
spec.add_dependency 'avro'
|
33
|
+
# For stubbing and custom matchers
|
34
|
+
spec.add_development_dependency 'rspec'
|
35
|
+
end
|
data/run_benchmark
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
echo 'Starting test of rails application...'
|
6
|
+
# Start the rails application
|
7
|
+
echo 'Starting rails application...'
|
8
|
+
pushd example/rails_app >/dev/null
|
9
|
+
nodenv local v0.10 >/dev/null
|
10
|
+
bundle exec rake db:reset RAILS_ENV=development
|
11
|
+
bundle exec unicorn -c config/unicorn.rb -E development -D
|
12
|
+
sleep 1
|
13
|
+
popd >/dev/null
|
14
|
+
echo 'Rails application started'
|
15
|
+
|
16
|
+
# Test publishing via the rails application
|
17
|
+
siege -c 10 -r 10 -q -b "http://localhost:8080/beavers POST beaver[name]=`date '+%m/%d/%y %H:%M:%S'`"
|
18
|
+
sleep 4
|
19
|
+
|
20
|
+
# Stop the rails application
|
21
|
+
echo 'Stopping rails application...'
|
22
|
+
pushd example/rails_app >/dev/null
|
23
|
+
kill `cat tmp/pids/unicorn.pid`
|
24
|
+
popd >/dev/null
|
25
|
+
echo 'Rails application stopped'
|
26
|
+
echo 'Rails application test complete'
|
27
|
+
echo ''
|
28
|
+
echo ''
|
29
|
+
|
30
|
+
# Test standalone publishing and consuming
|
31
|
+
echo 'Starting standalone publishing and consuming benchmark...'
|
32
|
+
pushd example/non_rails_app >/dev/null
|
33
|
+
bin/benchmark
|
34
|
+
popd >/dev/null
|
35
|
+
echo 'Benchmark complete'
|
data/run_example
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
# Start consumer on the non-rails application
|
6
|
+
echo 'Starting non rails application consumer...'
|
7
|
+
pushd example/non_rails_app >/dev/null
|
8
|
+
bundle >/dev/null
|
9
|
+
bundle exec rake
|
10
|
+
bundle exec rabbit_feed consume --environment development --require `pwd`/lib/non_rails_app.rb --daemon --verbose
|
11
|
+
sleep 1
|
12
|
+
popd >/dev/null
|
13
|
+
echo 'Non rails application consumer started'
|
14
|
+
|
15
|
+
# Start consumer on the rails application
|
16
|
+
echo 'Starting rails application consumer...'
|
17
|
+
pushd example/rails_app >/dev/null
|
18
|
+
bundle >/dev/null
|
19
|
+
bundle exec rake db:reset
|
20
|
+
bundle exec rake db:reset RAILS_ENV=test
|
21
|
+
bundle exec rake
|
22
|
+
bundle exec rabbit_feed consume --environment development --daemon --verbose
|
23
|
+
sleep 1
|
24
|
+
popd >/dev/null
|
25
|
+
echo 'Rails application consumer started'
|
26
|
+
|
27
|
+
# Start the rails application
|
28
|
+
echo 'Starting rails application...'
|
29
|
+
pushd example/rails_app >/dev/null
|
30
|
+
nodenv local v0.10 >/dev/null
|
31
|
+
bundle exec unicorn -c config/unicorn.rb -D
|
32
|
+
sleep 1
|
33
|
+
popd >/dev/null
|
34
|
+
echo 'Rails application started'
|
35
|
+
|
36
|
+
# Trigger an event
|
37
|
+
echo 'Triggering event...'
|
38
|
+
curl -silent -H -X POST http://localhost:8080/beavers -d "beaver[name]=`date '+%m/%d/%y %H:%M:%S'`" >/dev/null
|
39
|
+
echo 'Event triggered'
|
40
|
+
|
41
|
+
sleep 3
|
42
|
+
|
43
|
+
# Stop consumer on the non-rails application
|
44
|
+
echo 'Stopping non rails application consumer...'
|
45
|
+
pushd example/non_rails_app >/dev/null
|
46
|
+
kill `cat tmp/pids/rabbit_feed.pid`
|
47
|
+
popd >/dev/null
|
48
|
+
echo 'Non rails application consumer stopped'
|
49
|
+
|
50
|
+
# Stop consumer on the rails application
|
51
|
+
echo 'Stopping rails application consumer...'
|
52
|
+
pushd example/rails_app >/dev/null
|
53
|
+
kill `cat tmp/pids/rabbit_feed.pid`
|
54
|
+
popd >/dev/null
|
55
|
+
echo 'Rails application consumer stopped'
|
56
|
+
|
57
|
+
# Stop the rails application
|
58
|
+
echo 'Stopping rails application...'
|
59
|
+
pushd example/rails_app >/dev/null
|
60
|
+
kill `cat tmp/pids/unicorn.pid`
|
61
|
+
popd >/dev/null
|
62
|
+
echo 'Rails application stopped'
|
data/run_recovery_test
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
# Grant the session sudo access
|
6
|
+
sudo date
|
7
|
+
|
8
|
+
# In a separate process enable/disable the loopback interface
|
9
|
+
echo 'Starting process that will periodically disable lo0...'
|
10
|
+
sudo sh -c "while true; do ifconfig lo0 down; sleep 0.1; ifconfig lo0 up; sleep 0.5; done" &
|
11
|
+
disabling_pid=$!
|
12
|
+
|
13
|
+
# Test standalone publishing and consuming
|
14
|
+
echo 'Starting standalone publishing and consuming benchmark...'
|
15
|
+
pushd example/non_rails_app >/dev/null
|
16
|
+
bin/benchmark
|
17
|
+
popd >/dev/null
|
18
|
+
echo 'Benchmark complete'
|
19
|
+
|
20
|
+
# Kill the process that was toggling lo0 and ensure lo0 is enabled
|
21
|
+
function cleanup {
|
22
|
+
sudo kill $disabling_pid
|
23
|
+
sudo ifconfig lo0 up
|
24
|
+
echo 'Restored lo0'
|
25
|
+
}
|
26
|
+
trap cleanup EXIT
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Feature:
|
2
|
+
As a developer
|
3
|
+
I want to be able to publish and consume events
|
4
|
+
|
5
|
+
Scenario: I can publish and consume events
|
6
|
+
Given I am consuming
|
7
|
+
When I publish an event
|
8
|
+
Then I receive that event
|
9
|
+
|
10
|
+
Scenario: When an event cannot be consumed it remains on the queue
|
11
|
+
Given I am consuming
|
12
|
+
When I publish an event that cannot be processed by the consumer
|
13
|
+
Then the event remains on the queue
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
step 'I am consuming' do
|
4
|
+
set_event_routing
|
5
|
+
initialize_queue
|
6
|
+
@consumer_thread = Thread.new{ RabbitFeed::Consumer.run }
|
7
|
+
end
|
8
|
+
|
9
|
+
step 'I publish an event' do
|
10
|
+
set_event_definitions
|
11
|
+
publish 'test'
|
12
|
+
end
|
13
|
+
|
14
|
+
step 'I receive that event' do
|
15
|
+
event = wait_for_event
|
16
|
+
assert_event_presence event
|
17
|
+
end
|
18
|
+
|
19
|
+
step 'I publish an event that cannot be processed by the consumer' do
|
20
|
+
set_event_definitions
|
21
|
+
publish 'test_failure'
|
22
|
+
end
|
23
|
+
|
24
|
+
step 'the event remains on the queue' do
|
25
|
+
event = nil
|
26
|
+
2.times { event = wait_for_event }
|
27
|
+
assert_event_presence event
|
28
|
+
end
|
29
|
+
|
30
|
+
module Turnip::Steps
|
31
|
+
|
32
|
+
def initialize_queue
|
33
|
+
RabbitFeed::ProducerConnection.with_connection{|connection|}
|
34
|
+
RabbitFeed::ConsumerConnection.with_connection{|connection|}
|
35
|
+
end
|
36
|
+
|
37
|
+
def publish event_name
|
38
|
+
@event_text = "#{event_name}_#{Time.now.iso8601(6)}"
|
39
|
+
RabbitFeed::Producer.publish_event event_name, { 'field' => @event_text }
|
40
|
+
end
|
41
|
+
|
42
|
+
def assert_event_presence event
|
43
|
+
expect(event).to_not be_nil
|
44
|
+
expect(event.field).to eq @event_text
|
45
|
+
end
|
46
|
+
|
47
|
+
def wait_for_event
|
48
|
+
begin
|
49
|
+
Timeout::timeout(5.0) do
|
50
|
+
until @consumed_events.any? do
|
51
|
+
sleep 0.1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
rescue Timeout::Error
|
55
|
+
end
|
56
|
+
@consumed_events.pop
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_event_definitions
|
60
|
+
EventDefinitions do
|
61
|
+
define_event('test', version: '1.0.0') do
|
62
|
+
defined_as do
|
63
|
+
'The test event'
|
64
|
+
end
|
65
|
+
payload_contains do
|
66
|
+
field('field', type: 'string', definition: 'The field')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
define_event('test_failure', version: '1.0.0') do
|
70
|
+
defined_as do
|
71
|
+
'The test failure event'
|
72
|
+
end
|
73
|
+
payload_contains do
|
74
|
+
field('field', type: 'string', definition: 'The field')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def set_event_routing
|
81
|
+
consumed_events = []
|
82
|
+
@consumed_events = consumed_events
|
83
|
+
|
84
|
+
EventRouting do
|
85
|
+
accept_from('rabbit_feed') do
|
86
|
+
event('test') do |event|
|
87
|
+
consumed_events << event
|
88
|
+
end
|
89
|
+
event('test_failure') do |event|
|
90
|
+
consumed_events << event
|
91
|
+
raise 'event processing failure'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|