rabbit_feed 0.3.1
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.
- 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
|