fluffle 0.3.1 → 0.4.0
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 +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