rt-tackle 1.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: de0f2580c2937c203f50d01d0a8e7a66c8ad4cbe
4
- data.tar.gz: 249a5fabc8c8dc812a69d8541ae3ab7c8e046d3e
3
+ metadata.gz: 2b957a205e2dd52731c5a94cd871aa56e2f6a3e8
4
+ data.tar.gz: 2457adef2b1e810c72a5eee49706ce9ea5b5d483
5
5
  SHA512:
6
- metadata.gz: 784cb5cfec47ace9f60d6ddabdb5b7d117f31e76cba8c38b6960b318ca73cca851ec39f5d84c16f64df9485db5b63b24db467c83f89e155e80aab007a8712b3b
7
- data.tar.gz: 099fac7e24bc267a4c6556e1706c46fde7d823a007215b66e5842d077add917b48d8830d2b75aa50d0efb69a946b31fa1a7e11bdc765db90e3f3a7b5ac40ddc8
6
+ metadata.gz: bf96bfc2e3acde0a9b3351c602136322063e44344ecb01e46fd2d9e5732508db36807eb562dc79232b767ee40a406d87779f6c30bd73d439fb4d63cfaa859917
7
+ data.tar.gz: 88220350832e5214e7120089828ebb4d174b420247e89a29b8b5c0a2c092d353036ec6de66899511951dc9b21d5bd4eeb3f13b7a31766c87953e404f20bd6a90
data/README.md CHANGED
@@ -5,6 +5,15 @@
5
5
  Tackles the problem of processing asynchronous jobs in reliable manner
6
6
  by relying on RabbitMQ.
7
7
 
8
+ You should also take a look at [Elixir Tackle](https://github.com/renderedtext/ex-tackle).
9
+
10
+ ## Why should I use tackle?
11
+
12
+ - It is ideal for fast microservice prototyping
13
+ - It uses sane defaults for queue and exchange creation
14
+ - It retries messages that fail to be processed
15
+ - It stores unprocessed messages into a __dead__ queue for later inspection
16
+
8
17
  ## Installation
9
18
 
10
19
  Add this line to your application's Gemfile:
@@ -13,9 +22,7 @@ Add this line to your application's Gemfile:
13
22
  gem "rt-tackle", :require => "tackle"
14
23
  ```
15
24
 
16
- ## Usage
17
-
18
- ### Publishing a message
25
+ ## Publishing messages
19
26
 
20
27
  With tackle, you can publish a message to an AMQP exchange. For example, to
21
28
  publish `"Hello World!"` do the following:
@@ -44,10 +51,12 @@ options = {
44
51
  Tackle.publish("Hello World!", options)
45
52
  ```
46
53
 
47
- ### Consume messages
54
+ ## Consume messages
48
55
 
49
56
  Tackle enables you to connect to an AMQP exchange and consume messages from it.
50
57
 
58
+ ![Tackle consumer](docs/consumer.png)
59
+
51
60
  ```ruby
52
61
  require "tackle"
53
62
 
@@ -80,8 +89,6 @@ The above code snippet creates the following AMQP resources:
80
89
  where your service can't consume the message, tackle will store them in a
81
90
  dedicated dead queue. You can consume this messages manually.
82
91
 
83
- ![Tackle consumer](docs/consumer.png)
84
-
85
92
  You can pass additional configuration to tackle in order to control the number
86
93
  of retries, and the delay between each retry.
87
94
 
@@ -125,6 +132,66 @@ Tackle.consume(options) do |message|
125
132
  end
126
133
  ```
127
134
 
135
+ ## Manually ack-ing messages
136
+
137
+ By default, Tackle assumes that a message was successfully processed if no
138
+ exceptions were raised in the consume block. This behaviour is well suited for
139
+ handling unknown exceptions.
140
+
141
+ Sometimes however, we want to send a message to the retry queue without raising
142
+ an exception (and polluting our exception tracker with false positives).
143
+
144
+ For this purpose, tackle can be configured to consume messages in a "manual ack"
145
+ fashion. Pass `:manual_ack => true` to the consumer to activate the manual_ack
146
+ mode.
147
+
148
+ ```ruby
149
+ require "tackle"
150
+
151
+ options = {
152
+ :url => "amqp://localhost",
153
+ :exchange => "users",
154
+ :routing_key => "signed-up",
155
+ :service => "user-mailer"
156
+ :manual_ack => true
157
+ }
158
+
159
+ Tackle.consume(options) do |message|
160
+ puts message
161
+
162
+ Tackle::ACK
163
+ end
164
+ ```
165
+
166
+ When Tackle consumes messages in the manual_ack mode, the return value of the
167
+ consumer block must be either `Tackle::ACK` or `Tackle::NACK`. In case the
168
+ response is `Tackle::NACK` the message is put on the retry queue.
169
+
170
+ ```ruby
171
+ require "tackle"
172
+
173
+ options = {
174
+ :url => "amqp://localhost",
175
+ :exchange => "numbers",
176
+ :routing_key => "positive-numbers",
177
+ :service => "number-processor",
178
+ :manual_ack => true
179
+ }
180
+
181
+ Tackle.consume(options) do |message|
182
+ # accept only positive numbers
183
+
184
+ if message["value"].even?
185
+ Tackle::ACK
186
+ else
187
+ Tackle::NACK
188
+ end
189
+ end
190
+ ```
191
+
192
+ If neither Tackle::ACK nor Tackle::NACK are returned, tackle assumes
193
+ that the response is negative.
194
+
128
195
  ## Development
129
196
 
130
197
  After checking out the repo, run `bin/setup` to install dependencies. Then,
@@ -10,6 +10,7 @@ module Tackle
10
10
  attr_reader :retry_delay
11
11
  attr_reader :logger
12
12
  attr_reader :exception_handler
13
+ attr_reader :manual_ack
13
14
 
14
15
  def initialize(params = {})
15
16
  # required
@@ -22,10 +23,15 @@ module Tackle
22
23
  @retry_limit = params[:retry_limit] || 8
23
24
  @retry_delay = params[:retry_delay] || 30
24
25
  @logger = params[:logger] || Logger.new(STDOUT)
26
+ @manual_ack = params.fetch(:manual_ack, false)
25
27
 
26
28
  @exception_handler = params[:exception_handler]
27
29
  end
28
30
 
31
+ def manual_ack?
32
+ @manual_ack == true
33
+ end
34
+
29
35
  end
30
36
  end
31
37
  end
@@ -43,20 +43,28 @@ module Tackle
43
43
  def process_message(message, &block)
44
44
  message.log_info "Calling message processor"
45
45
 
46
- block.call(message.payload)
46
+ response = block.call(message.payload)
47
47
 
48
- message.ack
49
- rescue Exception => ex
50
- message.log_error "Failed to process message. Received exception '#{ex}'"
51
-
52
- redeliver_message(message)
48
+ unless @params.manual_ack?
49
+ response = Tackle::ACK
50
+ end
53
51
 
54
- message.nack
52
+ case response
53
+ when Tackle::ACK
54
+ message.ack
55
+ when Tackle::NACK
56
+ redeliver_message(message, "Received Tackle::NACK")
57
+ else
58
+ raise "Response must be either Tackle::ACK or Tackle::NACK"
59
+ end
60
+ rescue Exception => ex
61
+ redeliver_message(message, "Received exception '#{ex}'")
55
62
 
56
63
  raise ex
57
64
  end
58
65
 
59
- def redeliver_message(message)
66
+ def redeliver_message(message, reason)
67
+ message.log_error "Failed to process message. #{reason}"
60
68
  message.log_error "Retry count #{message.retry_count}/#{@params.retry_limit}"
61
69
 
62
70
  if message.retry_count < @params.retry_limit
@@ -64,6 +72,8 @@ module Tackle
64
72
  else
65
73
  @dead_queue.publish(message)
66
74
  end
75
+
76
+ message.nack
67
77
  end
68
78
 
69
79
  end
@@ -1,3 +1,3 @@
1
1
  module Tackle
2
- VERSION = "1.0"
2
+ VERSION = "1.1.0".freeze
3
3
  end
data/lib/tackle.rb CHANGED
@@ -7,6 +7,9 @@ module Tackle
7
7
  require "tackle/publisher"
8
8
  require "tackle/consumer"
9
9
 
10
+ ACK = :ack
11
+ NACK = :nack
12
+
10
13
  module_function
11
14
 
12
15
  def consume(params = {}, &block)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rt-tackle
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.0'
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rendered Text
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-09-10 00:00:00.000000000 Z
11
+ date: 2017-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny