sneakers_exponential_retry 0.1.0 → 0.2.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: af906d8bafee5024ee77370c828d92a22628ecdc
4
- data.tar.gz: 20a9007c85f5317d311f65a9a4f7a4988aebe6ae
3
+ metadata.gz: 383c16547be12323af1e50d4a68895cf6b9b0468
4
+ data.tar.gz: 4791aa18b3aa580856516226dc6bf5f440e281d3
5
5
  SHA512:
6
- metadata.gz: a6df19505aeff4c55d4c13d32686543da6ad73a4ee4b2fe2ac7de38eb44c911c8b2becf996acbc01e31ac6734b3c98a4a43b184bfe1ab2b5d00d020cb7b5a9c0
7
- data.tar.gz: f6ec2b59258761e81d0ca4f378762aa6129f278fcde47204ddd0b07c132dc4ae74ac1466730f0bd223dfec7752ae5c691fade4e74444bc9ab7a52c9fe4916037
6
+ metadata.gz: f33ce2504df5dc2bf284dbb38aa45a9605f5146e95915439ecb91f4eaac3315303da7ef6692e6cd7ad13bdc28963569bae827f295a63f3c99269eb5f818c7ab0
7
+ data.tar.gz: d8597d129e0a9bb472dec754f6181f1a13956204444dc3c7df3b0cf58941fbb404a349cc5b76b947a1680ebc1058a7474d345b8d31d9d4b5ad441adbec7bdbd3
data/README.md CHANGED
@@ -2,22 +2,6 @@
2
2
 
3
3
  Exponential Retry Handler for [Sneakers](https://github.com/jondot/sneakers) that just works.
4
4
 
5
- ## Installation
6
-
7
- Add this line to your application's Gemfile:
8
-
9
- ```ruby
10
- gem 'sneakers_exponential_retry'
11
- ```
12
-
13
- And then execute:
14
-
15
- $ bundle
16
-
17
- Or install it yourself as:
18
-
19
- $ gem install sneakers_exponential_retry
20
-
21
5
  ## Usage
22
6
 
23
7
  Configure your Sneakers by the following:
@@ -25,7 +9,7 @@ Configure your Sneakers by the following:
25
9
  ```ruby
26
10
  require 'sneakers_exponential_retry'
27
11
 
28
- Sneakers.configure :handler => SneakersExponentialRetry,
12
+ Sneakers.configure :handler => SneakersExponentialRetry::Handler,
29
13
  :handler_options => {
30
14
  :max_retry_count => 3,
31
15
  :logger => Sneakers.logger
@@ -41,9 +25,44 @@ Sneakers.configure :handler => SneakersExponentialRetry,
41
25
  - `max_retry_count`: (optional) Max retry count, default to 14
42
26
  - `logger`: (optional) logger instance, default to nil, which would not log anything related to retrying.
43
27
 
28
+
29
+ ## Installation
30
+
31
+ Add this line to your application's Gemfile:
32
+
33
+ ```ruby
34
+ gem 'sneakers_exponential_retry'
35
+ ```
36
+
37
+ And then execute:
38
+
39
+ $ bundle
40
+
41
+ Or install it yourself as:
42
+
43
+ $ gem install sneakers_exponential_retry
44
+
45
+
44
46
  ## How it works:
45
47
 
46
- TODO
48
+ (`SneakersExponentialRetry` is inspired by [this blogpost](https://gagnechris.wordpress.com/2015/09/19/easy-retries-with-rabbitmq/))
49
+
50
+ `SneakersExponentialRetry` handles the behavior of retrying failed jobs exponentially by:
51
+
52
+ 1. On initializing:
53
+ - Create a retry exchange, which is named as `#{queue_name}-retry-ex`
54
+ - Create a retry queue, which is named as `#{queue_name}-retry-queue`
55
+ - Set the `x-dead-letter-exchange` of retry queue to the original job exchange
56
+ - Bind the retry queue to the retry exchange
57
+
58
+ 2. Whenever a job fails, `SneakersExponentialRetry` would:
59
+ - if retry count <= `max_retry_count`
60
+ - publish the job to retry exchange, with an exponential expiration timeout
61
+ - the retry exchange would push the job into our retry queue
62
+ - after the timeout, the job would be published back to the `dead-letter-exchange` of the retry queue, which is our original exchange, so that the job would be retried
63
+
64
+ - if retry count > `max_retry_count`
65
+ - reject the job
47
66
 
48
67
  ## Testing:
49
68
 
@@ -1,97 +1,100 @@
1
1
  require "sneakers_exponential_retry/version"
2
2
 
3
- class ExponentialRetry
4
- MINUTE = 60 * 1000
5
- DEFAULT_MAX_RETRY_COUNT = 14
6
-
7
- def initialize(channel, queue, opts)
8
- @channel = channel
9
- @max_retry_count = calculate_max_retry_count(opts)
10
- @retry_exchange = create_retry_exchange(queue.name)
11
- @logger = opts[:handler_options] ? opts[:handler_options][:logger] : nil
12
-
13
- create_retry_queue(queue.name, opts[:exchange])
14
- .bind(@retry_exchange, :routing_key => '#')
15
- end
16
-
17
- def calculate_max_retry_count opts
18
- handler_options = opts[:handler_options] || {}
19
- ( handler_options[:max_retry_count] || DEFAULT_MAX_RETRY_COUNT ).to_i
20
- end
21
- private :calculate_max_retry_count
22
-
23
- def create_retry_exchange queue_name
24
- @channel.exchange("#{queue_name}-retry-ex",
25
- :type => 'topic',
26
- :durable => true)
27
- end
28
- private :create_retry_exchange
29
-
30
- def create_retry_queue queue_name, exchange_name
31
- @channel.queue(
32
- "#{queue_name}-retry-queue",
33
- durable: true,
34
- arguments: {
35
- :'x-dead-letter-exchange' => exchange_name
36
- }
37
- )
38
- end
39
- private :create_retry_queue
3
+ module SneakersExponentialRetry
4
+ class Handler
5
+ MINUTE = 60 * 1000
6
+ DEFAULT_MAX_RETRY_COUNT = 14
7
+
8
+ def initialize(channel, queue, opts)
9
+ @channel = channel
10
+ @max_retry_count = calculate_max_retry_count(opts)
11
+ @retry_exchange = create_retry_exchange(queue.name)
12
+ @logger = opts[:handler_options] ? opts[:handler_options][:logger] : nil
13
+
14
+ create_retry_queue(queue.name, opts[:exchange])
15
+ .bind(@retry_exchange, :routing_key => '#')
16
+ end
40
17
 
41
- def acknowledge(hdr, props, msg)
42
- @channel.acknowledge(hdr.delivery_tag, false)
43
- end
18
+ def calculate_max_retry_count opts
19
+ handler_options = opts[:handler_options] || {}
20
+ ( handler_options[:max_retry_count] || DEFAULT_MAX_RETRY_COUNT ).to_i
21
+ end
22
+ private :calculate_max_retry_count
44
23
 
45
- def reject(hdr, props, msg, requeue=false)
46
- @channel.reject(hdr.delivery_tag, requeue)
47
- end
24
+ def create_retry_exchange queue_name
25
+ @channel.exchange("#{queue_name}-retry-ex",
26
+ :type => 'topic',
27
+ :durable => true)
28
+ end
29
+ private :create_retry_exchange
30
+
31
+ def create_retry_queue queue_name, exchange_name
32
+ @channel.queue(
33
+ "#{queue_name}-retry-queue",
34
+ durable: true,
35
+ arguments: {
36
+ :'x-dead-letter-exchange' => exchange_name
37
+ }
38
+ )
39
+ end
40
+ private :create_retry_queue
48
41
 
49
- def error(hdr, props, msg, err)
50
- handle_failing_message(hdr, props, msg, err)
51
- end
42
+ def acknowledge(hdr, props, msg)
43
+ @channel.acknowledge(hdr.delivery_tag, false)
44
+ end
52
45
 
53
- def handle_failing_message hdr, props, msg, error
54
- retry_count = get_retry_count(props[:headers])
55
- if retry_count >= @max_retry_count
56
- reject(hdr, props, msg)
57
- return
46
+ def reject(hdr, props, msg, requeue=false)
47
+ @channel.reject(hdr.delivery_tag, requeue)
58
48
  end
59
49
 
50
+ def error(hdr, props, msg, err)
51
+ handle_failing_message(hdr, props, msg, err)
52
+ end
60
53
 
61
- @retry_exchange.publish(msg,
62
- :headers => {
63
- 'retry-count' => retry_count + 1
64
- },
65
- :routing_key => hdr.routing_key,
66
- :expiration => expiration_time(retry_count))
67
- log_retry(retry_count)
68
- acknowledge(hdr, props, msg)
69
- end
70
- private :handle_failing_message
54
+ def handle_failing_message hdr, props, msg, error
55
+ retry_count = get_retry_count(props[:headers])
56
+ if retry_count >= @max_retry_count
57
+ reject(hdr, props, msg)
58
+ return
59
+ end
60
+
61
+
62
+ @retry_exchange.publish(msg,
63
+ :headers => {
64
+ 'retry-count' => retry_count + 1
65
+ },
66
+ :routing_key => hdr.routing_key,
67
+ :expiration => expiration_time(retry_count))
68
+ log_retry(retry_count)
69
+ acknowledge(hdr, props, msg)
70
+ end
71
+ private :handle_failing_message
71
72
 
72
- def log_retry count
73
- return unless @logger
74
- @logger.info do
75
- "retry_count: #{count + 1}"
73
+ def log_retry count
74
+ return unless @logger
75
+ @logger.info do
76
+ "retry_count: #{count + 1}"
77
+ end
76
78
  end
77
- end
78
- private :log_retry
79
+ private :log_retry
79
80
 
80
- def get_retry_count headers
81
- return 0 unless headers
82
- headers['retry-count'].to_i
83
- end
84
- private :get_retry_count
81
+ def get_retry_count headers
82
+ return 0 unless headers
83
+ headers['retry-count'].to_i
84
+ end
85
+ private :get_retry_count
85
86
 
86
- def expiration_time retry_count
87
- (2 ** retry_count) * MINUTE
88
- end
89
- private :expiration_time
87
+ def expiration_time retry_count
88
+ (2 ** retry_count) * MINUTE
89
+ end
90
+ private :expiration_time
90
91
 
91
- def timeout(hdr, props, msg)
92
- reject(hdr, props, msg)
93
- end
92
+ def timeout(hdr, props, msg)
93
+ reject(hdr, props, msg)
94
+ end
94
95
 
95
- def noop(hdr, props, msg)
96
+ def noop(hdr, props, msg)
97
+ end
96
98
  end
97
99
  end
100
+
@@ -1,3 +1,3 @@
1
1
  module SneakersExponentialRetry
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sneakers_exponential_retry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yang-Hsing Lin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-08-18 00:00:00.000000000 Z
11
+ date: 2016-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler