rt-tackle 1.0 → 1.1.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: 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