amqp-subscribe-many 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/Gemfile.lock +4 -0
- data/Makefile +1 -1
- data/README.md +74 -0
- data/Rakefile +2 -2
- data/amqp-subscribe-many.gemspec +7 -3
- data/img/amqp-subscribe-many.png +0 -0
- data/lib/messaging/client.rb +6 -4
- data/lib/messaging/producer.rb +3 -3
- data/test/test_helper.rb +6 -0
- metadata +30 -18
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -25,6 +25,9 @@ GEM
|
|
25
25
|
rdoc (3.12)
|
26
26
|
json (~> 1.4)
|
27
27
|
redcarpet (2.1.1)
|
28
|
+
simplecov (0.4.2)
|
29
|
+
simplecov-html (~> 0.4.4)
|
30
|
+
simplecov-html (0.4.5)
|
28
31
|
yard (0.8.2.1)
|
29
32
|
|
30
33
|
PLATFORMS
|
@@ -37,4 +40,5 @@ DEPENDENCIES
|
|
37
40
|
minitest (>= 3.0)
|
38
41
|
mocha
|
39
42
|
redcarpet
|
43
|
+
simplecov
|
40
44
|
yard
|
data/Makefile
CHANGED
data/README.md
CHANGED
@@ -2,3 +2,77 @@ Publish One, Subscribe Many
|
|
2
2
|
===========
|
3
3
|
|
4
4
|
[![Build Status](https://secure.travis-ci.org/brendanhay/amqp-subscribe-many.png)](http://travis-ci.org/brendanhay/amqp-subscribe-many)
|
5
|
+
|
6
|
+
|
7
|
+
Table of Contents
|
8
|
+
-----------------
|
9
|
+
|
10
|
+
* [Introduction](#introduction)
|
11
|
+
* [Testing](#test)
|
12
|
+
* [Contribute](#contribute)
|
13
|
+
* [Licence](#licence)
|
14
|
+
|
15
|
+
|
16
|
+
<a name="introduction" />
|
17
|
+
|
18
|
+
Introduction
|
19
|
+
------------
|
20
|
+
|
21
|
+
This gem is a _reference implementation_ for a Publish One, Subscribe Many pattern which is in use at [SoundCloud](http://soundcloud.com).
|
22
|
+
|
23
|
+
The pattern assumes a single load balanced publish point and multiple direct consumption points as outlined in the follow diagram:
|
24
|
+
|
25
|
+
![Publish One, Subscribe Many](https://raw.github.com/brendanhay/amqp-subscribe-many/master/img/amqp-subscribe-many.png)
|
26
|
+
|
27
|
+
In this scenario, a worker's single publish connection is load balanced to a broker. The workers have consumer connections to all possible brokers ensuring
|
28
|
+
that no matter which broker a message ends up on the consumer can receive it.
|
29
|
+
|
30
|
+
Exchanges, queues, and bindings need to be declared upon connection, ensuring that all brokers will converge on the same set of routing information.
|
31
|
+
|
32
|
+
Some buzzwor{th,d}y advantages of this setup include:
|
33
|
+
|
34
|
+
* Partitioned Load
|
35
|
+
* Horizontal Scalability
|
36
|
+
* High Availability (across the logical topology)
|
37
|
+
|
38
|
+
Drawbacks:
|
39
|
+
|
40
|
+
* More complex client code
|
41
|
+
* Another hop in the form of the load-balancer
|
42
|
+
* A node going down, needs to be brought back up to access the messages
|
43
|
+
|
44
|
+
A common error is to conflate availability and durability. In this case, they are treated as seperate concerns with the form of availability on offer refering to the ability of all connected clients to get a message from point to point under most conditions.
|
45
|
+
|
46
|
+
Durability requires messages to be published as persistent and manual intervention in the case of a node crash to bring the failed node (or disk) back into consumer awareness, to ensure the messages are flushed.
|
47
|
+
|
48
|
+
The code in this repository can be used either as a gem available on [rubygems.org](rubygems.org/gems/amqp-subscribe-many) or as a guide to implement the above pattern using the ruby-amqp gem.
|
49
|
+
|
50
|
+
See `./examples/run` for usage.
|
51
|
+
|
52
|
+
|
53
|
+
<a name="test" />
|
54
|
+
|
55
|
+
Testing
|
56
|
+
-------
|
57
|
+
|
58
|
+
Run all the tests:
|
59
|
+
|
60
|
+
```shell
|
61
|
+
make test
|
62
|
+
```
|
63
|
+
|
64
|
+
|
65
|
+
<a name="contribute" />
|
66
|
+
|
67
|
+
Contribute
|
68
|
+
----------
|
69
|
+
|
70
|
+
For any problems, comments or feedback please create an issue [here on GitHub](github.com/brendanhay/amqp-subscribe-many/issues).
|
71
|
+
|
72
|
+
|
73
|
+
<a name="licence" />
|
74
|
+
|
75
|
+
Licence
|
76
|
+
-------
|
77
|
+
|
78
|
+
amqp-subscribe-many is released under the [Mozilla Public License Version 2.0](http://www.mozilla.org/MPL/)
|
data/Rakefile
CHANGED
@@ -22,7 +22,7 @@ require "rake"
|
|
22
22
|
require "rake/testtask"
|
23
23
|
|
24
24
|
Rake::TestTask.new do |t|
|
25
|
-
t.libs
|
25
|
+
t.libs << "lib"
|
26
26
|
t.test_files = FileList["test/*_test.rb"]
|
27
27
|
t.verbose = true
|
28
28
|
end
|
@@ -49,7 +49,7 @@ Jeweler::RubygemsDotOrgTasks.new
|
|
49
49
|
|
50
50
|
Jeweler::Tasks.new do |gem|
|
51
51
|
gem.name = "amqp-subscribe-many"
|
52
|
-
gem.version = "0.1.
|
52
|
+
gem.version = "0.1.5"
|
53
53
|
gem.homepage = "http://github.com/brendanhay/amqp-subscribe-many"
|
54
54
|
gem.license = "MPL"
|
55
55
|
gem.summary = "An implementation of the publish one, subscribe many pattern"
|
data/amqp-subscribe-many.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{amqp-subscribe-many}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = [%q{brendanhay}]
|
12
|
-
s.date = %q{2012-07
|
12
|
+
s.date = %q{2012-09-07}
|
13
13
|
s.description = %q{Codifies best practices and configuration when consuming from multiple AMQP brokers simultaneously}
|
14
14
|
s.email = %q{brendan@soundcloud.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
|
|
29
29
|
"examples/duplex_processor.rb",
|
30
30
|
"examples/producer_processor.rb",
|
31
31
|
"examples/run",
|
32
|
+
"img/amqp-subscribe-many.png",
|
32
33
|
"lib/messaging.rb",
|
33
34
|
"lib/messaging/client.rb",
|
34
35
|
"lib/messaging/configuration.rb",
|
@@ -42,7 +43,7 @@ Gem::Specification.new do |s|
|
|
42
43
|
s.homepage = %q{http://github.com/brendanhay/amqp-subscribe-many}
|
43
44
|
s.licenses = [%q{MPL}]
|
44
45
|
s.require_paths = [%q{lib}]
|
45
|
-
s.rubygems_version = %q{1.8.
|
46
|
+
s.rubygems_version = %q{1.8.6}
|
46
47
|
s.summary = %q{An implementation of the publish one, subscribe many pattern}
|
47
48
|
|
48
49
|
if s.respond_to? :specification_version then
|
@@ -52,6 +53,7 @@ Gem::Specification.new do |s|
|
|
52
53
|
s.add_runtime_dependency(%q<amqp>, [">= 0.9.6"])
|
53
54
|
s.add_development_dependency(%q<bundler>, [">= 0"])
|
54
55
|
s.add_development_dependency(%q<minitest>, [">= 3.0"])
|
56
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
55
57
|
s.add_development_dependency(%q<mocha>, [">= 0"])
|
56
58
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
57
59
|
s.add_development_dependency(%q<redcarpet>, [">= 0"])
|
@@ -60,6 +62,7 @@ Gem::Specification.new do |s|
|
|
60
62
|
s.add_dependency(%q<amqp>, [">= 0.9.6"])
|
61
63
|
s.add_dependency(%q<bundler>, [">= 0"])
|
62
64
|
s.add_dependency(%q<minitest>, [">= 3.0"])
|
65
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
63
66
|
s.add_dependency(%q<mocha>, [">= 0"])
|
64
67
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
65
68
|
s.add_dependency(%q<redcarpet>, [">= 0"])
|
@@ -69,6 +72,7 @@ Gem::Specification.new do |s|
|
|
69
72
|
s.add_dependency(%q<amqp>, [">= 0.9.6"])
|
70
73
|
s.add_dependency(%q<bundler>, [">= 0"])
|
71
74
|
s.add_dependency(%q<minitest>, [">= 3.0"])
|
75
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
72
76
|
s.add_dependency(%q<mocha>, [">= 0"])
|
73
77
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
74
78
|
s.add_dependency(%q<redcarpet>, [">= 0"])
|
Binary file
|
data/lib/messaging/client.rb
CHANGED
@@ -39,7 +39,7 @@ module Messaging
|
|
39
39
|
log.error("Connection to #{uri.inspect} lost, reconnecting")
|
40
40
|
|
41
41
|
if (402..540).include?(error.reply_code)
|
42
|
-
raise(MessagingError, "
|
42
|
+
raise(MessagingError, "Connection exception: #{error.reply_text.inspect}")
|
43
43
|
end
|
44
44
|
|
45
45
|
conn.periodically_reconnect(delay)
|
@@ -137,11 +137,13 @@ module Messaging
|
|
137
137
|
# @return [Boolean]
|
138
138
|
# @api private
|
139
139
|
def default_exchange?(name)
|
140
|
-
["
|
140
|
+
["",
|
141
|
+
"amq.default",
|
142
|
+
"amq.direct",
|
141
143
|
"amq.fanout",
|
142
144
|
"amq.topic",
|
143
|
-
"
|
144
|
-
"
|
145
|
+
"amq.headers",
|
146
|
+
"amq.match"].include?(name)
|
145
147
|
end
|
146
148
|
end
|
147
149
|
|
data/lib/messaging/producer.rb
CHANGED
@@ -11,16 +11,16 @@ module Messaging
|
|
11
11
|
# @param payload [Object]
|
12
12
|
# @return [Messaging::Producer]
|
13
13
|
# @api public
|
14
|
-
def publish(exchange, type, key, payload)
|
14
|
+
def publish(exchange, type, key, payload, options = {})
|
15
15
|
ex = producer_exchanges[exchange] ||=
|
16
16
|
declare_exchange(producer_channel, exchange, type, config.exchange_options)
|
17
17
|
|
18
18
|
log.debug("Publishing to exchange #{exchange.inspect} via #{key.inspect}")
|
19
19
|
|
20
|
-
ex.publish(payload, {
|
20
|
+
ex.publish(payload, options.merge({
|
21
21
|
:exchange => exchange,
|
22
22
|
:routing_key => key
|
23
|
-
})
|
23
|
+
}))
|
24
24
|
|
25
25
|
self
|
26
26
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amqp-subscribe-many
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07
|
12
|
+
date: 2012-09-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: amqp
|
16
|
-
requirement: &
|
16
|
+
requirement: &70256241444900 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.9.6
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70256241444900
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: bundler
|
27
|
-
requirement: &
|
27
|
+
requirement: &70256241482320 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70256241482320
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: minitest
|
38
|
-
requirement: &
|
38
|
+
requirement: &70256241481600 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,21 @@ dependencies:
|
|
43
43
|
version: '3.0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70256241481600
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: simplecov
|
49
|
+
requirement: &70256241480400 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70256241480400
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: mocha
|
49
|
-
requirement: &
|
60
|
+
requirement: &70256241477160 !ruby/object:Gem::Requirement
|
50
61
|
none: false
|
51
62
|
requirements:
|
52
63
|
- - ! '>='
|
@@ -54,10 +65,10 @@ dependencies:
|
|
54
65
|
version: '0'
|
55
66
|
type: :development
|
56
67
|
prerelease: false
|
57
|
-
version_requirements: *
|
68
|
+
version_requirements: *70256241477160
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: jeweler
|
60
|
-
requirement: &
|
71
|
+
requirement: &70256241476540 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ! '>='
|
@@ -65,10 +76,10 @@ dependencies:
|
|
65
76
|
version: '0'
|
66
77
|
type: :development
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *70256241476540
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: redcarpet
|
71
|
-
requirement: &
|
82
|
+
requirement: &70256241475320 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ! '>='
|
@@ -76,10 +87,10 @@ dependencies:
|
|
76
87
|
version: '0'
|
77
88
|
type: :development
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *70256241475320
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: yard
|
82
|
-
requirement: &
|
93
|
+
requirement: &70256241490260 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ! '>='
|
@@ -87,7 +98,7 @@ dependencies:
|
|
87
98
|
version: '0'
|
88
99
|
type: :development
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
101
|
+
version_requirements: *70256241490260
|
91
102
|
description: Codifies best practices and configuration when consuming from multiple
|
92
103
|
AMQP brokers simultaneously
|
93
104
|
email: brendan@soundcloud.com
|
@@ -109,6 +120,7 @@ files:
|
|
109
120
|
- examples/duplex_processor.rb
|
110
121
|
- examples/producer_processor.rb
|
111
122
|
- examples/run
|
123
|
+
- img/amqp-subscribe-many.png
|
112
124
|
- lib/messaging.rb
|
113
125
|
- lib/messaging/client.rb
|
114
126
|
- lib/messaging/configuration.rb
|
@@ -133,7 +145,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
133
145
|
version: '0'
|
134
146
|
segments:
|
135
147
|
- 0
|
136
|
-
hash:
|
148
|
+
hash: 2625083279973371652
|
137
149
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
150
|
none: false
|
139
151
|
requirements:
|
@@ -142,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
154
|
version: '0'
|
143
155
|
requirements: []
|
144
156
|
rubyforge_project:
|
145
|
-
rubygems_version: 1.8.
|
157
|
+
rubygems_version: 1.8.6
|
146
158
|
signing_key:
|
147
159
|
specification_version: 3
|
148
160
|
summary: An implementation of the publish one, subscribe many pattern
|