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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 122f80facd1bb3cf22f70ff33546da4ae228f72e
4
- data.tar.gz: b7939ddcb8bfc94962cea7d6e2b6257afe29eb73
3
+ metadata.gz: 23e4f19afd95059c202ab4bc0af6272d02a7c9d0
4
+ data.tar.gz: 7ebfc0c7c29f5a947413d870e7652b745636a57a
5
5
  SHA512:
6
- metadata.gz: a90deb17fc848e89a176a47a27050ee30a60b5b59746c149cbdb11b8da025cfca8735e55336c640a968be663e1b73a584663813f2b18486784c34bd05587f0e3
7
- data.tar.gz: d8b0d2d9226d1a5f2e9611c4f448161d30a33f1bb3e38f1458e64e62264678d4cfc6b9aa53b0bc6f059dde5a80d27693efa32f52b32985214b8169063d7c7717
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
 
@@ -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
- @pending_responses = Concurrent::Map.new
31
+ if confirms
32
+ @pending_confirms = Concurrent::Map.new
33
+ confirm_select
34
+ end
30
35
 
31
- self.subscribe
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
- ivar = Concurrent::IVar.new
106
- @pending_responses[id] = ivar
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 ivar.incomplete?
113
- method = payload['method']
114
- arity = (payload['params'] && payload['params'].length) || 0
115
- raise Errors::TimeoutError.new("Timed out waiting for response to `#{method}/#{arity}'")
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),
@@ -1,3 +1,3 @@
1
1
  module Fluffle
2
- VERSION = '0.3.1'
2
+ VERSION = '0.4.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluffle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dirk Gadsden