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 +4 -4
- data/README.md +37 -18
- data/lib/sneakers_exponential_retry.rb +83 -80
- data/lib/sneakers_exponential_retry/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 383c16547be12323af1e50d4a68895cf6b9b0468
|
4
|
+
data.tar.gz: 4791aa18b3aa580856516226dc6bf5f440e281d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
.
|
15
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
42
|
+
def acknowledge(hdr, props, msg)
|
43
|
+
@channel.acknowledge(hdr.delivery_tag, false)
|
44
|
+
end
|
52
45
|
|
53
|
-
|
54
|
-
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
73
|
+
def log_retry count
|
74
|
+
return unless @logger
|
75
|
+
@logger.info do
|
76
|
+
"retry_count: #{count + 1}"
|
77
|
+
end
|
76
78
|
end
|
77
|
-
|
78
|
-
private :log_retry
|
79
|
+
private :log_retry
|
79
80
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
def expiration_time retry_count
|
88
|
+
(2 ** retry_count) * MINUTE
|
89
|
+
end
|
90
|
+
private :expiration_time
|
90
91
|
|
91
|
-
|
92
|
-
|
93
|
-
|
92
|
+
def timeout(hdr, props, msg)
|
93
|
+
reject(hdr, props, msg)
|
94
|
+
end
|
94
95
|
|
95
|
-
|
96
|
+
def noop(hdr, props, msg)
|
97
|
+
end
|
96
98
|
end
|
97
99
|
end
|
100
|
+
|
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.
|
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-
|
11
|
+
date: 2016-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|