fluffle 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/examples/client.rb +1 -1
- data/lib/fluffle/client.rb +67 -13
- data/lib/fluffle/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23e4f19afd95059c202ab4bc0af6272d02a7c9d0
|
4
|
+
data.tar.gz: 7ebfc0c7c29f5a947413d870e7652b745636a57a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0ce2b422e356596c1dad872f56ce106360f82e0c5079f3372817a586af11de7a0c0409ed6578f43b8ca21b8837b12c33b69469cd20c971e33b98ccb2023355d
|
7
|
+
data.tar.gz: 80c7da2ff18ece5e1754a36a595cff627c0f925d84b2c652c352064e891ff52c2209c5eee56f795ee00bc748fbbb78270bbb4ec9de719f1c860b97558c5fa3c2
|
data/examples/client.rb
CHANGED
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
3
|
|
4
4
|
require 'fluffle'
|
5
5
|
|
6
|
-
client = Fluffle::Client.new url: 'amqp://localhost'
|
6
|
+
client = Fluffle::Client.new url: 'amqp://localhost', confirms: true
|
7
7
|
# You can also pass `connection:` to use an existing Bunny connection:
|
8
8
|
# Fluffle::Client.new(connection: Bunny.new('amqp://localhost', heartbeat: 2))
|
9
9
|
|
data/lib/fluffle/client.rb
CHANGED
@@ -9,12 +9,14 @@ module Fluffle
|
|
9
9
|
class Client
|
10
10
|
include Connectable
|
11
11
|
|
12
|
+
attr_reader :confirms
|
12
13
|
attr_accessor :default_timeout
|
13
14
|
attr_accessor :logger
|
14
15
|
|
15
|
-
def initialize(url: nil, connection: nil)
|
16
|
+
def initialize(url: nil, connection: nil, confirms: false)
|
16
17
|
self.connect(url || connection)
|
17
18
|
|
19
|
+
@confirms = confirms
|
18
20
|
@default_timeout = 5
|
19
21
|
@logger = Fluffle.logger
|
20
22
|
|
@@ -26,9 +28,13 @@ module Fluffle
|
|
26
28
|
# Used for generating unique message IDs
|
27
29
|
@prng = Random.new
|
28
30
|
|
29
|
-
|
31
|
+
if confirms
|
32
|
+
@pending_confirms = Concurrent::Map.new
|
33
|
+
confirm_select
|
34
|
+
end
|
30
35
|
|
31
|
-
|
36
|
+
@pending_responses = Concurrent::Map.new
|
37
|
+
subscribe
|
32
38
|
end
|
33
39
|
|
34
40
|
def subscribe
|
@@ -45,6 +51,22 @@ module Fluffle
|
|
45
51
|
end
|
46
52
|
end
|
47
53
|
|
54
|
+
def confirm_select
|
55
|
+
handle_confirm = ->(tag, _multiple, nack) do
|
56
|
+
ivar = @pending_confirms.delete tag
|
57
|
+
|
58
|
+
if ivar
|
59
|
+
ivar.set nack
|
60
|
+
else
|
61
|
+
self.logger.error "Missing confirm IVar: tag=#{tag}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Set the channel in confirmation mode so that we can receive confirms
|
66
|
+
# of published messages
|
67
|
+
@channel.confirm_select handle_confirm
|
68
|
+
end
|
69
|
+
|
48
70
|
# Fetch and set the `IVar` with a response from the server. This method is
|
49
71
|
# called from the reply queue's background thread; the main thread will
|
50
72
|
# normally be waiting for the `IVar` to be set.
|
@@ -102,25 +124,57 @@ module Fluffle
|
|
102
124
|
def publish_and_wait(payload, queue:, timeout:)
|
103
125
|
id = payload['id']
|
104
126
|
|
105
|
-
|
106
|
-
@pending_responses[id] =
|
107
|
-
|
108
|
-
self.publish payload, queue: queue
|
109
|
-
|
110
|
-
response = ivar.value timeout
|
127
|
+
response_ivar = Concurrent::IVar.new
|
128
|
+
@pending_responses[id] = response_ivar
|
111
129
|
|
112
|
-
if
|
113
|
-
|
114
|
-
|
115
|
-
|
130
|
+
if confirms
|
131
|
+
with_confirmation(timeout: timeout) { publish payload, queue: queue }
|
132
|
+
else
|
133
|
+
publish payload, queue: queue
|
116
134
|
end
|
117
135
|
|
136
|
+
response = response_ivar.value timeout
|
137
|
+
raise_incomplete(payload, 'response') if response_ivar.incomplete?
|
138
|
+
|
118
139
|
return response
|
119
140
|
ensure
|
120
141
|
# Don't leak the `IVar` if it timed out
|
121
142
|
@pending_responses.delete id
|
122
143
|
end
|
123
144
|
|
145
|
+
# Returns a nice formatted description of a payload with its method name
|
146
|
+
# and arity
|
147
|
+
def describe_payload(payload)
|
148
|
+
method = payload['method']
|
149
|
+
arity = (payload['params'] && payload['params'].length) || 0
|
150
|
+
|
151
|
+
"#{method}/#{arity}"
|
152
|
+
end
|
153
|
+
|
154
|
+
# Wraps a block (which should publish a message) with a blocking check
|
155
|
+
# that the client received a confirmation from the RabbitMQ server
|
156
|
+
# that the message that was received and routed successfully
|
157
|
+
def with_confirmation(timeout:)
|
158
|
+
tag = @channel.next_publish_seq_no
|
159
|
+
confirm_ivar = Concurrent::IVar.new
|
160
|
+
@pending_confirms[tag] = confirm_ivar
|
161
|
+
|
162
|
+
yield
|
163
|
+
|
164
|
+
nack = confirm_ivar.value timeout
|
165
|
+
if confirm_ivar.incomplete?
|
166
|
+
raise_incomplete payload, 'confirm'
|
167
|
+
elsif nack
|
168
|
+
raise Errors::NackError.new('Received nack from confirmation')
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# event_name - String describing what we timed out waiting for, should
|
173
|
+
# be 'response' or 'confirm'
|
174
|
+
def raise_incomplete(payload, event_name)
|
175
|
+
raise Errors::TimeoutError.new("Timed out waiting for #{event_name} to `#{describe_payload(payload)}'")
|
176
|
+
end
|
177
|
+
|
124
178
|
def publish(payload, queue:)
|
125
179
|
opts = {
|
126
180
|
routing_key: Fluffle.request_queue_name(queue),
|
data/lib/fluffle/version.rb
CHANGED