rabbit_feed 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/Brewfile +4 -0
  5. data/DEVELOPING.md +140 -0
  6. data/Gemfile +15 -0
  7. data/Gemfile.lock +121 -0
  8. data/LICENSE.txt +9 -0
  9. data/README.md +304 -0
  10. data/Rakefile +30 -0
  11. data/bin/bundle +3 -0
  12. data/bin/rabbit_feed +11 -0
  13. data/example/non_rails_app/.rspec +1 -0
  14. data/example/non_rails_app/Gemfile +7 -0
  15. data/example/non_rails_app/Gemfile.lock +56 -0
  16. data/example/non_rails_app/Rakefile +5 -0
  17. data/example/non_rails_app/bin/benchmark +63 -0
  18. data/example/non_rails_app/bin/bundle +3 -0
  19. data/example/non_rails_app/config/rabbit_feed.yml +8 -0
  20. data/example/non_rails_app/lib/non_rails_app.rb +32 -0
  21. data/example/non_rails_app/lib/non_rails_app/event_handler.rb +10 -0
  22. data/example/non_rails_app/log/.keep +0 -0
  23. data/example/non_rails_app/spec/lib/non_rails_app/event_handler_spec.rb +14 -0
  24. data/example/non_rails_app/spec/lib/non_rails_app/event_routing_spec.rb +14 -0
  25. data/example/non_rails_app/spec/spec_helper.rb +31 -0
  26. data/example/non_rails_app/tmp/pids/.keep +0 -0
  27. data/example/rails_app/.gitignore +17 -0
  28. data/example/rails_app/.node-version +1 -0
  29. data/example/rails_app/.rspec +1 -0
  30. data/example/rails_app/Gemfile +36 -0
  31. data/example/rails_app/Gemfile.lock +173 -0
  32. data/example/rails_app/README.rdoc +28 -0
  33. data/example/rails_app/Rakefile +6 -0
  34. data/example/rails_app/app/assets/images/.keep +0 -0
  35. data/example/rails_app/app/assets/javascripts/application.js +16 -0
  36. data/example/rails_app/app/assets/javascripts/beavers.js.coffee +3 -0
  37. data/example/rails_app/app/assets/stylesheets/application.css +15 -0
  38. data/example/rails_app/app/assets/stylesheets/beavers.css.scss +3 -0
  39. data/example/rails_app/app/assets/stylesheets/scaffolds.css.scss +69 -0
  40. data/example/rails_app/app/controllers/application_controller.rb +5 -0
  41. data/example/rails_app/app/controllers/beavers_controller.rb +81 -0
  42. data/example/rails_app/app/controllers/concerns/.keep +0 -0
  43. data/example/rails_app/app/helpers/application_helper.rb +2 -0
  44. data/example/rails_app/app/helpers/beavers_helper.rb +2 -0
  45. data/example/rails_app/app/mailers/.keep +0 -0
  46. data/example/rails_app/app/models/.keep +0 -0
  47. data/example/rails_app/app/models/beaver.rb +2 -0
  48. data/example/rails_app/app/models/concerns/.keep +0 -0
  49. data/example/rails_app/app/views/beavers/_form.html.erb +21 -0
  50. data/example/rails_app/app/views/beavers/edit.html.erb +6 -0
  51. data/example/rails_app/app/views/beavers/index.html.erb +25 -0
  52. data/example/rails_app/app/views/beavers/index.json.jbuilder +4 -0
  53. data/example/rails_app/app/views/beavers/new.html.erb +5 -0
  54. data/example/rails_app/app/views/beavers/show.html.erb +9 -0
  55. data/example/rails_app/app/views/beavers/show.json.jbuilder +1 -0
  56. data/example/rails_app/app/views/layouts/application.html.erb +14 -0
  57. data/example/rails_app/bin/bundle +3 -0
  58. data/example/rails_app/bin/rails +4 -0
  59. data/example/rails_app/bin/rake +4 -0
  60. data/example/rails_app/config.ru +4 -0
  61. data/example/rails_app/config/application.rb +25 -0
  62. data/example/rails_app/config/boot.rb +4 -0
  63. data/example/rails_app/config/database.yml +22 -0
  64. data/example/rails_app/config/environment.rb +5 -0
  65. data/example/rails_app/config/environments/development.rb +83 -0
  66. data/example/rails_app/config/environments/test.rb +39 -0
  67. data/example/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  68. data/example/rails_app/config/initializers/cookies_serializer.rb +3 -0
  69. data/example/rails_app/config/initializers/filter_parameter_logging.rb +4 -0
  70. data/example/rails_app/config/initializers/inflections.rb +16 -0
  71. data/example/rails_app/config/initializers/mime_types.rb +4 -0
  72. data/example/rails_app/config/initializers/rabbit_feed.rb +43 -0
  73. data/example/rails_app/config/initializers/session_store.rb +3 -0
  74. data/example/rails_app/config/initializers/wrap_parameters.rb +14 -0
  75. data/example/rails_app/config/locales/en.yml +23 -0
  76. data/example/rails_app/config/rabbit_feed.yml +8 -0
  77. data/example/rails_app/config/routes.rb +58 -0
  78. data/example/rails_app/config/secrets.yml +18 -0
  79. data/example/rails_app/config/unicorn.rb +4 -0
  80. data/example/rails_app/db/migrate/20140424102400_create_beavers.rb +9 -0
  81. data/example/rails_app/db/schema.rb +22 -0
  82. data/example/rails_app/db/seeds.rb +7 -0
  83. data/example/rails_app/lib/assets/.keep +0 -0
  84. data/example/rails_app/lib/event_handler.rb +7 -0
  85. data/example/rails_app/lib/tasks/.keep +0 -0
  86. data/example/rails_app/log/.keep +0 -0
  87. data/example/rails_app/public/404.html +67 -0
  88. data/example/rails_app/public/422.html +67 -0
  89. data/example/rails_app/public/500.html +66 -0
  90. data/example/rails_app/public/favicon.ico +0 -0
  91. data/example/rails_app/public/robots.txt +5 -0
  92. data/example/rails_app/spec/controllers/beavers_controller_spec.rb +32 -0
  93. data/example/rails_app/spec/event_routing_spec.rb +15 -0
  94. data/example/rails_app/spec/spec_helper.rb +51 -0
  95. data/example/rails_app/test/controllers/.keep +0 -0
  96. data/example/rails_app/test/controllers/beavers_controller_test.rb +49 -0
  97. data/example/rails_app/test/fixtures/.keep +0 -0
  98. data/example/rails_app/test/fixtures/beavers.yml +7 -0
  99. data/example/rails_app/test/helpers/.keep +0 -0
  100. data/example/rails_app/test/helpers/beavers_helper_test.rb +4 -0
  101. data/example/rails_app/test/integration/.keep +0 -0
  102. data/example/rails_app/test/mailers/.keep +0 -0
  103. data/example/rails_app/test/models/.keep +0 -0
  104. data/example/rails_app/test/models/beaver_test.rb +7 -0
  105. data/example/rails_app/test/test_helper.rb +13 -0
  106. data/example/rails_app/tmp/pids/.keep +0 -0
  107. data/example/rails_app/vendor/assets/javascripts/.keep +0 -0
  108. data/example/rails_app/vendor/assets/stylesheets/.keep +0 -0
  109. data/lib/dsl.rb +9 -0
  110. data/lib/rabbit_feed.rb +41 -0
  111. data/lib/rabbit_feed/client.rb +181 -0
  112. data/lib/rabbit_feed/configuration.rb +50 -0
  113. data/lib/rabbit_feed/connection_concern.rb +95 -0
  114. data/lib/rabbit_feed/consumer.rb +14 -0
  115. data/lib/rabbit_feed/consumer_connection.rb +108 -0
  116. data/lib/rabbit_feed/event.rb +43 -0
  117. data/lib/rabbit_feed/event_definitions.rb +98 -0
  118. data/lib/rabbit_feed/event_routing.rb +90 -0
  119. data/lib/rabbit_feed/producer.rb +47 -0
  120. data/lib/rabbit_feed/producer_connection.rb +65 -0
  121. data/lib/rabbit_feed/testing_support/rspec_matchers/publish_event.rb +90 -0
  122. data/lib/rabbit_feed/testing_support/testing_helpers.rb +16 -0
  123. data/lib/rabbit_feed/version.rb +3 -0
  124. data/logo.png +0 -0
  125. data/rabbit_feed.gemspec +35 -0
  126. data/run_benchmark +35 -0
  127. data/run_example +62 -0
  128. data/run_recovery_test +26 -0
  129. data/spec/features/connectivity.feature +13 -0
  130. data/spec/features/step_definitions/connectivity_steps.rb +96 -0
  131. data/spec/fixtures/configuration.yml +14 -0
  132. data/spec/lib/rabbit_feed/client_spec.rb +116 -0
  133. data/spec/lib/rabbit_feed/configuration_spec.rb +121 -0
  134. data/spec/lib/rabbit_feed/connection_concern_spec.rb +116 -0
  135. data/spec/lib/rabbit_feed/consumer_connection_spec.rb +85 -0
  136. data/spec/lib/rabbit_feed/event_definitions_spec.rb +139 -0
  137. data/spec/lib/rabbit_feed/event_routing_spec.rb +121 -0
  138. data/spec/lib/rabbit_feed/event_spec.rb +33 -0
  139. data/spec/lib/rabbit_feed/producer_connection_spec.rb +72 -0
  140. data/spec/lib/rabbit_feed/producer_spec.rb +57 -0
  141. data/spec/lib/rabbit_feed/testing_support/rspec_matchers/publish_event_spec.rb +60 -0
  142. data/spec/lib/rabbit_feed/testing_support/testing_helper_spec.rb +34 -0
  143. data/spec/spec_helper.rb +58 -0
  144. data/spec/support/shared_examples_for_connections.rb +40 -0
  145. metadata +305 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b89c207774f809ccb829ba29d9b11299dc2872b0
4
+ data.tar.gz: 9ff5943d611beed002969fcad6b62e9d75b4f1c2
5
+ SHA512:
6
+ metadata.gz: 2e612b191caae6071e6e5df07e0fc45f081353a68eae365be1ed5548a41d7b23ac82395436ca7e494d3f53d94724e4941041edd9986ed706d48b0e3e26e949ca
7
+ data.tar.gz: d76e833bf491449b3b641dd2346aa1f7b76de28acf7e1ff02d3f63416af311ec1d464a7a8f84f8fff3509251b0edc1c4150118b1318256a45e642a71b598c0f5
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ # Bundler directory
2
+ .bundle
3
+ # Gem package directory
4
+ pkg
5
+ # OSX dotfile
6
+ .DS_Store
7
+ # Log files
8
+ *.log
9
+ *.iml
10
+ .idea/
11
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ -r rutabaga
2
+ --order rand
3
+ --color
data/Brewfile ADDED
@@ -0,0 +1,4 @@
1
+ # MQ server
2
+ rabbitmq
3
+ # For load testing
4
+ siege
data/DEVELOPING.md ADDED
@@ -0,0 +1,140 @@
1
+ # Developing RabbitFeed
2
+
3
+ ## Prerequisites
4
+
5
+ ### Ruby
6
+
7
+ RabbitFeed has been tested on Ruby v2.0.
8
+
9
+ Install the required gems with
10
+
11
+ gem install bundler
12
+ bundle install
13
+
14
+ ### RabbitMQ running locally
15
+
16
+ brew project
17
+ rabbitmq-server
18
+
19
+ The management interface can be found [here](http://localhost:15672/). The default login is `guest/guest`. You can view exchanges [here](http://localhost:15672/#/exchanges) and queues [here](http://localhost:15672/#/queues).
20
+
21
+
22
+ ## Running Tests
23
+
24
+ This will run the specs and the features:
25
+
26
+ bundle exec rake
27
+
28
+ ## Running the example project
29
+
30
+ After doing any dev work, it is good practice to verify you haven't broken the examples. Run the examples like this:
31
+
32
+ ./run_example
33
+
34
+ You should see something similar to the following output:
35
+
36
+ Starting non rails application consumer...
37
+ /opt/boxen/rbenv/versions/2.0.0-p451/bin/ruby -S rspec ./spec/lib/non_rails_app/event_handler_spec.rb
38
+ NonRailsApp::EventHandler - Consumed event: user_updates_beaver with payload: {"beaver_name"=>"beaver"}
39
+ .
40
+
41
+ Finished in 0.00349 seconds
42
+ 1 example, 0 failures
43
+
44
+ Randomized with seed 59391
45
+
46
+ Non rails application consumer started
47
+ Starting rails application consumer...
48
+ /opt/boxen/rbenv/versions/2.0.0-p451/bin/ruby -S rspec ./spec/controllers/beavers_controller_spec.rb
49
+ ...
50
+
51
+ Finished in 0.04397 seconds
52
+ 3 examples, 0 failures
53
+
54
+ Randomized with seed 18883
55
+
56
+ Rails application consumer started
57
+ Starting rails application...
58
+ Rails application started
59
+ Triggering event...
60
+ NonRailsApp::EventHandler - Consumed event: user_creates_beaver with payload: {"application"=>"rails_app", "host"=>"macjfleck.home", "environment"=>"development", "version"=>"1.0.0", "name"=>"user_creates_beaver", "created_at_utc"=>"2014-05-05T14:16:44.045395Z", "beaver_name"=>"05/05/14 15:16:43"}
61
+ Event triggered
62
+ RailsApp::EventHandler - Consumed event: application_acknowledges_event with payload: {"application"=>"non_rails_app", "host"=>"macjfleck.home", "environment"=>"development", "version"=>"1.0.0", "name"=>"application_acknowledges_event", "created_at_utc"=>"2014-05-05T14:16:44.057279Z", "beaver_name"=>"05/05/14 15:16:43", "event_name"=>"user_creates_beaver"}
63
+ Stopping non rails application consumer...
64
+ Non rails application consumer stopped
65
+ Stopping rails application consumer...
66
+ Rails application consumer stopped
67
+ Stopping rails application...
68
+ Rails application stopped
69
+
70
+ ## Performance Benchmarking
71
+
72
+ There is a script that can be run to benchmark the tool. It benchmarks three areas:
73
+
74
+ 1. Producing events during HTTP requests within a rails application (using [siege](http://www.joedog.org/siege-home/))
75
+ 2. Producing events directly
76
+ 3. Consuming events
77
+
78
+ To run the benchmarking script
79
+
80
+ brew project
81
+ ./run_benchmark
82
+
83
+ As of 20140925, running the benchmark on this hardware:
84
+
85
+ MacBook Pro Retina, Mid 2012
86
+ Processor 2.6 GHz Intel Core i7
87
+ Memory 8 GB 1600 MHz DDR3
88
+ Software OS X 10.8.5 (12F45)
89
+
90
+ Results in this output:
91
+
92
+ Starting test of rails application...
93
+ Starting rails application...
94
+ -- create_table("beavers", {:force=>true})
95
+ -> 0.0140s
96
+ -- initialize_schema_migrations_table()
97
+ -> 0.0196s
98
+ Rails application started
99
+ done.
100
+
101
+ Transactions: 200 hits
102
+ Availability: 100.00 %
103
+ Elapsed time: 1.33 secs
104
+ Data transferred: 0.16 MB
105
+ Response time: 0.06 secs
106
+ Transaction rate: 150.38 trans/sec
107
+ Throughput: 0.12 MB/sec
108
+ Concurrency: 8.76
109
+ Successful transactions: 100
110
+ Failed transactions: 0
111
+ Longest transaction: 0.36
112
+ Shortest transaction: 0.00
113
+
114
+ Stopping rails application...
115
+ Rails application stopped
116
+ Rails application test complete
117
+
118
+
119
+ Starting standalone publishing and consuming benchmark...
120
+ Publishing 5000 events...
121
+ user system total real
122
+ 2.460000 0.310000 2.770000 ( 2.779719)
123
+ Consuming 5000 events...
124
+ user system total real
125
+ 2.380000 0.590000 2.970000 ( 3.500515)
126
+ Benchmark complete
127
+
128
+ ## Connection Recovery Testing
129
+
130
+ A critical piece of RabbitFeed is the ability to recover from network connectivity problems. This means...
131
+
132
+ * When publishing, all events that are published make it to the queue
133
+ * When consuming, the consumer re-establishes its connection to the queue automatically
134
+
135
+ To simulate network connectivity problems, there is a recovery test script that can be run like this:
136
+
137
+ brew project
138
+ ./run_recovery_test
139
+
140
+ The script will publish and then consume 5000 mesages with the network dropping out every half-second.
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rabbit_feed.gemspec
4
+ gemspec
5
+
6
+ group :development, :test do
7
+ gem 'pry-plus'
8
+ gem 'rake'
9
+ end
10
+
11
+ group :test do
12
+ gem 'codeclimate-test-reporter'
13
+ gem 'rutabaga'
14
+ gem 'timecop'
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,121 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rabbit_feed (0.3.1)
5
+ activemodel
6
+ activesupport
7
+ avro
8
+ bunny
9
+ connection_pool
10
+ pidfile
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ activemodel (4.1.6)
16
+ activesupport (= 4.1.6)
17
+ builder (~> 3.1)
18
+ activesupport (4.1.6)
19
+ i18n (~> 0.6, >= 0.6.9)
20
+ json (~> 1.7, >= 1.7.7)
21
+ minitest (~> 5.1)
22
+ thread_safe (~> 0.1)
23
+ tzinfo (~> 1.1)
24
+ amq-protocol (1.9.2)
25
+ avro (1.7.7)
26
+ multi_json
27
+ binding_of_caller (0.7.2)
28
+ debug_inspector (>= 0.0.1)
29
+ bond (0.4.3)
30
+ builder (3.2.2)
31
+ bunny (1.6.3)
32
+ amq-protocol (>= 1.9.2)
33
+ codeclimate-test-reporter (0.2.0)
34
+ simplecov (>= 0.7.1, < 1.0.0)
35
+ coderay (1.1.0)
36
+ columnize (0.3.6)
37
+ connection_pool (2.0.0)
38
+ debug_inspector (0.0.2)
39
+ debugger (1.6.6)
40
+ columnize (>= 0.3.1)
41
+ debugger-linecache (~> 1.2.0)
42
+ debugger-ruby_core_source (~> 1.3.2)
43
+ debugger-linecache (1.2.0)
44
+ debugger-ruby_core_source (1.3.2)
45
+ diff-lcs (1.2.5)
46
+ docile (1.1.2)
47
+ gherkin (2.12.2)
48
+ multi_json (~> 1.3)
49
+ i18n (0.6.11)
50
+ interception (0.3)
51
+ jist (1.5.1)
52
+ json
53
+ json (1.8.1)
54
+ method_source (0.8.2)
55
+ minitest (5.4.2)
56
+ multi_json (1.9.2)
57
+ pidfile (0.3.0)
58
+ pry (0.9.12.4)
59
+ coderay (~> 1.0)
60
+ method_source (~> 0.8)
61
+ slop (~> 3.4)
62
+ pry-debugger (0.2.2)
63
+ debugger (~> 1.3)
64
+ pry (~> 0.9.10)
65
+ pry-doc (0.4.6)
66
+ pry (>= 0.9)
67
+ yard (>= 0.8)
68
+ pry-docmore (0.1.1)
69
+ pry
70
+ pry-doc
71
+ pry-plus (1.0.0)
72
+ bond
73
+ jist
74
+ pry-debugger
75
+ pry-doc
76
+ pry-docmore
77
+ pry-rescue
78
+ pry-stack_explorer
79
+ pry-rescue (1.2.0)
80
+ interception (>= 0.3)
81
+ pry
82
+ pry-stack_explorer (0.4.9.1)
83
+ binding_of_caller (>= 0.7)
84
+ pry (>= 0.9.11)
85
+ rake (10.2.2)
86
+ rspec (2.14.1)
87
+ rspec-core (~> 2.14.0)
88
+ rspec-expectations (~> 2.14.0)
89
+ rspec-mocks (~> 2.14.0)
90
+ rspec-core (2.14.8)
91
+ rspec-expectations (2.14.5)
92
+ diff-lcs (>= 1.1.3, < 2.0)
93
+ rspec-mocks (2.14.6)
94
+ rutabaga (0.0.4)
95
+ turnip (>= 1.1.0)
96
+ simplecov (0.8.2)
97
+ docile (~> 1.1.0)
98
+ multi_json
99
+ simplecov-html (~> 0.8.0)
100
+ simplecov-html (0.8.0)
101
+ slop (3.4.7)
102
+ thread_safe (0.3.4)
103
+ timecop (0.4.4)
104
+ turnip (1.2.1)
105
+ gherkin (>= 2.5)
106
+ rspec (>= 2.0, < 4.0)
107
+ tzinfo (1.2.2)
108
+ thread_safe (~> 0.1)
109
+ yard (0.8.7.3)
110
+
111
+ PLATFORMS
112
+ ruby
113
+
114
+ DEPENDENCIES
115
+ codeclimate-test-reporter
116
+ pry-plus
117
+ rabbit_feed!
118
+ rake
119
+ rspec
120
+ rutabaga
121
+ timecop
data/LICENSE.txt ADDED
@@ -0,0 +1,9 @@
1
+ Copyright (c) 2013-2014 Simply Business
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,304 @@
1
+ # RabbitFeed
2
+
3
+ ![RabbitFeed logo](https://cloud.githubusercontent.com/assets/768254/3286432/b4e65e7e-f548-11e3-9c91-f7d04f489cf3.png)
4
+
5
+ A gem providing asynchronous event publish and subscribe capabilities with RabbitMQ.
6
+
7
+ ## Core concepts
8
+
9
+ * Fire and forget: Application can publish an event and it has no knowledge/care of how that event is consumed.
10
+ * Persistent events: Once an event has been published, it will persist until it has been processed successfully.
11
+ * Self-describing events: The event not only contains a payload, but also a schema that describes that payload.
12
+ * Multiple subscribers: Multiple applications can subscribe to the same events.
13
+ * Event versioning: Consumers can customize event handling based on the event version.
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ gem 'rabbit_feed', git: 'git@github.com:simplybusiness/rabbit_feed.git'
20
+
21
+ ### Configuration
22
+
23
+ Create a `config/rabbit_feed.yml` file. The following options can be specified:
24
+
25
+ environment:
26
+ host: RabbitMQ host
27
+ user: RabbitMQ user name
28
+ password: RabbitMQ password
29
+ application: Application name
30
+
31
+ Sample:
32
+
33
+ development:
34
+ host: localhost
35
+ user: guest
36
+ password: guest
37
+ application: beavers
38
+
39
+ ### Initialisation
40
+
41
+ If installing in a rails application, the following should be defined in `config/initializers/rabbit_feed.rb`:
42
+
43
+ ```ruby
44
+ RabbitFeed.instance_eval do
45
+ self.log = Logger.new (Rails.root.join 'log', 'rabbit_feed.log')
46
+ self.environment = Rails.env
47
+ self.configuration_file_path = Rails.root.join 'config', 'rabbit_feed.yml'
48
+ end
49
+ # Define the events (if producing)
50
+ EventDefinitions do
51
+ define_event('user_creates_beaver', version: '1.0.0') do
52
+ defined_as do
53
+ 'A beaver has been created'
54
+ end
55
+ payload_contains do
56
+ field('beaver_name', type: 'string', definition: 'The name of the beaver')
57
+ end
58
+ end
59
+ end
60
+ # Define the event routing (if consuming)
61
+ EventRouting do
62
+ accept_from('beavers') do
63
+ event('foo') do |event|
64
+ # Do something...
65
+ end
66
+ end
67
+ end
68
+ ```
69
+
70
+ ## Producing events
71
+
72
+ The producer defines the events and their payloads using the [Event Definitions DSL](https://github.com/simplybusiness/rabbit_feed#event-definitions-dsl). In a rails app, this can be defined in the [initialiser](https://github.com/simplybusiness/rabbit_feed#initialisation).
73
+
74
+ To produce an event:
75
+
76
+ ```ruby
77
+ require 'rabbit_feed'
78
+ RabbitFeed::Producer.publish_event 'Event name', { 'payload_field' => 'payload field value' }
79
+ ```
80
+
81
+ **Event name:** This tells you what the event is.
82
+
83
+ **Event payload:** This is the data about the event. This should be a hash.
84
+
85
+ The event will be published to the configured exchange on RabbitMQ (`amq.topic` by default) with a routing key having the pattern of: `[environment].[producer application name].[event name]`.
86
+
87
+ ### Returned Events
88
+
89
+ In the case that there are no consumers configured to subscribe to an event, the event will be returned to the producer. The returned event will be logged, and if your project uses [Airbrake](https://airbrake.io), an error will be reported there.
90
+
91
+ ### Testing the Producer
92
+
93
+ To prevent RabbitFeed from firing events during tests, add the following to `spec_helper.rb`:
94
+
95
+ ```ruby
96
+ config.before :each do
97
+ RabbitFeed::Producer.stub!
98
+ end
99
+ ```
100
+
101
+ #### RSpec
102
+
103
+ To verify that your application publishes an event, use the custom RSpec matcher provided with this application.
104
+
105
+ Add the following RSpec configuration to `spec_helper.rb`:
106
+
107
+ ```ruby
108
+ RSpec.configure do |config|
109
+ config.include(RabbitFeed::TestingSupport::RSpecMatchers)
110
+ end
111
+ ```
112
+
113
+ The expectation looks like this:
114
+
115
+ ```ruby
116
+ require 'spec_helper'
117
+
118
+ describe BeaversController do
119
+
120
+ describe 'POST create' do
121
+ it 'publishes a create event' do
122
+ expect{
123
+ post :create, beaver: { name: 'beaver' }
124
+ }.to publish_event('user_creates_beaver', { 'beaver_name' => 'beaver' })
125
+ end
126
+ end
127
+ end
128
+ ```
129
+
130
+ ## Consuming events
131
+
132
+ The consumer defines to which events it will subscribe as well as how it handles events using the [Event Routing DSL](https://github.com/simplybusiness/rabbit_feed#event-routing-dsl). In a rails app, this can be defined in the [initialiser](https://github.com/simplybusiness/rabbit_feed#initialisation).
133
+
134
+ An `Event` contains the following information:
135
+
136
+ `environment` The environment in which the event was created (e.g. development, test, production)
137
+ `application` The name of the application that generated the event (as specified in rabbit_feed.yml)
138
+ `version` The version of the event
139
+ `name` The name of the event
140
+ `host` The hostname of the server on which the event was generated
141
+ `created_at_utc` The time (in UTC) that the event was created
142
+ `payload` The payload of the event
143
+
144
+ ### Running the consumer
145
+
146
+ bundle exec rabbit_feed consume --environment development
147
+
148
+ More information about the consumer command line options can be found [here](https://github.com/simplybusiness/rabbit_feed#consumer).
149
+
150
+ ### Event Processing Errors
151
+
152
+ In the case that your consumer raises an error whilst processing an event, the error will be logged. If your project uses [Airbrake](https://airbrake.io), the error will also be reported there. The event that was being processed will remain on the RabbitMQ queue, and will be redelivered to the consumer until it is processed without error.
153
+
154
+ ### Testing the Consumer
155
+
156
+ If you want to test that your routes are behaving as expected without actually using RabbitMQ, you can include the module `TestHelpers` in your tests and then invoke `rabbit_feed_consumer.consume_event(event)`. Following is an example:
157
+
158
+ ```ruby
159
+ describe 'consuming events' do
160
+
161
+ include RabbitFeed::TestingSupport::TestingHelpers
162
+
163
+ accumulator = []
164
+
165
+ let(:define_route) do
166
+ EventRouting do
167
+ accept_from('app') do
168
+ event('ev') do |event|
169
+ accumulator << event
170
+ end
171
+ end
172
+ end
173
+ end
174
+
175
+ let(:event) { {'application' => 'app', 'name' => 'ev', 'stuff' => 'some_stuff'} }
176
+
177
+ before { define_route }
178
+
179
+ it 'route to the correct service' do
180
+ rabbit_feed_consumer.consume_event(event)
181
+ expect(accumulator.size).to eq(1)
182
+ end
183
+ end
184
+ ```
185
+
186
+ ## Command Line Tools
187
+
188
+ ### Event Publish
189
+
190
+ bundle exec bin/rabbit_feed produce --payload 'Event payload' --name 'Event name' --environment test --config spec/fixtures/configuration.yml --logfile test.log --require rabbit_feed.rb --verbose
191
+
192
+ Publishes an event. Note: until you've specified the [event definitions](https://github.com/simplybusiness/rabbit_feed#event-definitions-dsl), this will not publish any events. Options are as follows:
193
+
194
+ --payload The payload of the event
195
+ --name The name of the event
196
+ --environment The environment to run in
197
+ --config The location of the rabbit_feed configuration file
198
+ --logfile The location of the log file
199
+ --require The project file containing the dependancies
200
+ --verbose Turns on DEBUG logging
201
+ --help Print the available options
202
+
203
+ ### Consumer
204
+
205
+ bundle exec bin/rabbit_feed consume --environment test --config spec/fixtures/configuration.yml --logfile test.log --require rabbit_feed.rb --pidfile rabbit_feed.pid --verbose --daemon
206
+
207
+ Starts a consumer. Note: until you've specified the [event routing](https://github.com/simplybusiness/rabbit_feed#event-routing-dsl), this will not receive any events. Options are as follows:
208
+
209
+ --environment The environment to run in
210
+ --config The location of the rabbit_feed configuration file
211
+ --logfile The location of the log file
212
+ --require The project file containing the dependancies (only necessary if running with non-rails application)
213
+ --pidfile The location at which to write a pid file
214
+ --verbose Turns on DEBUG logging
215
+ --daemon Run the consumer as a daemon
216
+ --help Print the available options
217
+
218
+ ## Event Definitions DSL
219
+
220
+ Provides a means to define all events that are published by an application. Defines the event names and the payload associated with each event. The DSL is converted into a schema that is serialized along with the event payload, meaning the events are self-describing. This is accomplished using Apache [Avro](http://avro.apache.org/docs/current/). This also validates the event payload against its schema before it is published.
221
+
222
+ Event definitions are cumulative, meaning you can load multiple `EventDefinitions` blocks.
223
+
224
+ Here is an example DSL:
225
+
226
+ ```ruby
227
+ EventDefinitions do
228
+ define_event('user_creates_beaver', version: '1.0.0') do
229
+ defined_as do
230
+ 'A beaver has been created'
231
+ end
232
+ payload_contains do
233
+ field('beaver_name', type: 'string', definition: 'The name of the beaver')
234
+ end
235
+ end
236
+
237
+ define_event('user_updates_beaver', version: '1.0.0') do
238
+ defined_as do
239
+ 'A beaver has been updated'
240
+ end
241
+ payload_contains do
242
+ field('beaver_name', type: 'string', definition: 'The name of the beaver')
243
+ end
244
+ end
245
+ end
246
+ ```
247
+
248
+ This defines two events:
249
+
250
+ 1. `user_creates_beaver`
251
+ 2. `user_updates_beaver`
252
+
253
+ Each event has a mandatory string field in its payload, called `beaver_name`.
254
+
255
+ The available field types are described [here](http://avro.apache.org/docs/current/spec.html#schema_primitive).
256
+
257
+ Publishing a `user_creates_beaver` event would look like this:
258
+
259
+ ```ruby
260
+ RabbitFeed::Producer.publish_event 'user_creates_beaver', { 'beaver_name' => @beaver.name }
261
+ ```
262
+
263
+ ## Event Routing DSL
264
+
265
+ Provides a means for consumers to specify to which events it will subscribe as well as how it handles events. This is accomplished using a custom DSL backed by a RabbitMQ [topic](http://www.rabbitmq.com/tutorials/tutorial-five-ruby.html) exchange.
266
+
267
+ Event routing definitions are cumulative, meaning you can load multiple `EventRouting` blocks.
268
+
269
+ Here is an example DSL:
270
+
271
+ ```ruby
272
+ EventRouting do
273
+ accept_from('beavers') do
274
+ event('user_created_beaver') do |event|
275
+ puts event.payload
276
+ end
277
+ event('user_updated_beaver') do |event|
278
+ puts event.payload
279
+ end
280
+ end
281
+ end
282
+ ```
283
+
284
+ This will subscribe to specified events originating from the `beavers` application. We have specified that we would like to subcribe to `user_created_beaver` and `user_updated_beaver` events. If either event type is received, we have specified that its payload will be printed to the screen.
285
+
286
+ When the consumer is started, it will create its queue named using this pattern: `[environment].[consumer application name]`. It will bind the queue to the `amq.topic` exchange on the routing keys as defined in the event routing. In this example, it will bind on:
287
+
288
+ environment.beavers.user_created_beaver
289
+ environment.beavers.user_updated_beaver
290
+
291
+ _Note: The consumer queues will automatically expire (delete) after 7 days without any consumer connections. This is to prevent unused queues from hanging around once their associated consumer has been terminated._
292
+
293
+ ## Delivery Semantics
294
+
295
+ RabbitFeed provides 'at least once' delivery semantics. There are two use-cases where an event may be delivered more than once:
296
+
297
+ 1. If the subscriber raises an exception whilst processing an event, RabbitFeed will re-deliver the event to the subscriber until the event is processed without error.
298
+ 1. If an event is pushed to the subscriber, and the subscriber loses connectivity with RabbitMQ before it can send an acknowledgement back to RabbitMQ, RabbitMQ will push the event again once connectivity has been restored.
299
+
300
+ It is advisable to run RabbitFeed in a [clustered](https://www.rabbitmq.com/clustering.html) RabbitMQ environment to prevent the loss of messages in the case that a RabbitMQ node is lost. By default, RabbitFeed will declare queues to be mirrored across all nodes of the cluster.
301
+
302
+ ## Developing
303
+
304
+ _See [./DEVELOPING.md](./DEVELOPING.md) for instructions on how to develop RabbitFeed_