nagare-redis 0.4.0 → 0.5.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/Gemfile.lock +1 -1
- data/README.md +13 -0
- data/lib/nagare/config.rb +11 -3
- data/lib/nagare/listener_pool.rb +1 -3
- data/lib/nagare/redis_streams.rb +41 -4
- data/lib/nagare/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a74be4520fe261310cc782a2232ad5270ed572c4afbd98072241ef6dc1bc118c
|
4
|
+
data.tar.gz: f3d9391aae29591f9652e342034ce79959498a020596b01a4d4c3d40bf35d33a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9c5c5bfa26746f5a0d5c84446991aad2d3d3faf802e8c9222d61fb79b6f2aaecdf55b81654ec71571c5d978d1350bb8306c054db2e816106c9a730383c2b9e6
|
7
|
+
data.tar.gz: a973dc7583907a0b75d0c8e09dda57e799721eab302a3d1786e0c83293c1475baa37cbea8ccc3dbb36fd39a45e4c906bac33dea2b4980a36c7a733b7a919f96f
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -67,6 +67,19 @@ Nagare.configure do |config|
|
|
67
67
|
# and in the background
|
68
68
|
# Default: 3 threads
|
69
69
|
config.threads = 3
|
70
|
+
|
71
|
+
# Nagare can execute a proc for error handling. This enables you to
|
72
|
+
# use APM tools like New Relic or Appsignal with it.
|
73
|
+
# The proc takes 2 parameters, message and error.
|
74
|
+
# By default, nagare logs the error to stderr.
|
75
|
+
config.error_handler = proc do |message, error|
|
76
|
+
Appsignal.set_error(error);
|
77
|
+
end
|
78
|
+
|
79
|
+
# After exceeding the maximum number of retries, nagare moves the
|
80
|
+
# failing messages to a Dead Letter Queue stream.
|
81
|
+
# By default this stream is named 'dlq', but you can customize it.
|
82
|
+
config.dlq_stream = 'its_dead_jim'
|
70
83
|
end
|
71
84
|
```
|
72
85
|
|
data/lib/nagare/config.rb
CHANGED
@@ -5,13 +5,14 @@ module Nagare
|
|
5
5
|
# See the README for possible values and what they do
|
6
6
|
class Config
|
7
7
|
class << self
|
8
|
-
attr_accessor :group_name, :redis_url, :threads, :suffix, :min_idle_time
|
8
|
+
attr_accessor :group_name, :redis_url, :threads, :suffix, :min_idle_time,
|
9
|
+
:error_handler, :dlq_stream, :max_retries
|
9
10
|
|
10
11
|
# Runs code in the block passed in to configure Nagare and sets defaults
|
11
12
|
# when values are not set.
|
12
13
|
#
|
13
14
|
# returns [Nagare::Config] self
|
14
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
15
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize
|
15
16
|
def configure
|
16
17
|
yield(self)
|
17
18
|
@dead_consumer_timeout ||= 5000
|
@@ -20,9 +21,16 @@ module Nagare
|
|
20
21
|
@threads ||= 1
|
21
22
|
@suffix ||= nil
|
22
23
|
@min_idle_time ||= 600_000
|
24
|
+
@error_handler ||= proc do |message, error|
|
25
|
+
Nagare.logger.error "Failed to process message #{message}"
|
26
|
+
Nagare.logger.error error.message
|
27
|
+
Nagare.logger.error error.backtrace.join("\n")
|
28
|
+
end
|
29
|
+
@dlq_stream ||= 'dlq'
|
30
|
+
@max_retries ||= 10
|
23
31
|
self
|
24
32
|
end
|
25
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
33
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize
|
26
34
|
end
|
27
35
|
end
|
28
36
|
end
|
data/lib/nagare/listener_pool.rb
CHANGED
@@ -83,10 +83,8 @@ module Nagare
|
|
83
83
|
listeners.each do |listener|
|
84
84
|
invoke_listener(stream, message, listener)
|
85
85
|
rescue StandardError => e
|
86
|
-
logger.error e.message
|
87
|
-
logger.error e.backtrace.join("\n")
|
88
86
|
listener_failed = true
|
89
|
-
|
87
|
+
Nagare::Config.error_handler.call(message, e)
|
90
88
|
end
|
91
89
|
|
92
90
|
return if listener_failed
|
data/lib/nagare/redis_streams.rb
CHANGED
@@ -76,27 +76,64 @@ module Nagare
|
|
76
76
|
# @return [String] message id
|
77
77
|
def publish(stream, event_name, data)
|
78
78
|
stream = stream_name(stream)
|
79
|
-
connection.xadd(stream, { "#{event_name}": data })
|
79
|
+
connection.xadd(stream, { "#{event_name}": data.to_json })
|
80
80
|
end
|
81
81
|
|
82
82
|
##
|
83
83
|
# Claums the next message of the consumer group that is stuck
|
84
84
|
# (pending and past min_idle_time since being picked up)
|
85
85
|
#
|
86
|
-
# @param
|
86
|
+
# @param stream_prefix [String] name of the stream
|
87
87
|
# @param group [String] name of the consumer group
|
88
88
|
#
|
89
89
|
# @return [Array[Hash]] array containing the 1 message or empty
|
90
|
-
|
91
|
-
|
90
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
91
|
+
def claim_next_stuck_message(stream_prefix, group)
|
92
|
+
stream = stream_name(stream_prefix)
|
92
93
|
result = connection.xautoclaim(stream,
|
93
94
|
"#{stream}-#{group}",
|
94
95
|
"#{hostname}-#{thread_id}",
|
95
96
|
Nagare::Config.min_idle_time,
|
96
97
|
'0-0',
|
97
98
|
count: 1)
|
99
|
+
|
100
|
+
# Move message to DLQ if retried too much and get next one
|
101
|
+
if result['entries'].any?
|
102
|
+
message_id = result['entries'].first.first
|
103
|
+
if retry_count(stream_prefix, group,
|
104
|
+
message_id) > Nagare::Config.max_retries
|
105
|
+
move_to_dlq(stream_prefix, group, result['entries'].first)
|
106
|
+
return claim_next_stuck_message(stream, group)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
98
110
|
result['entries'] || []
|
99
111
|
end
|
112
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
113
|
+
|
114
|
+
##
|
115
|
+
# Uses XPENDING to verify the number of times the message was
|
116
|
+
# delivered
|
117
|
+
def retry_count(stream, group, message_id)
|
118
|
+
stream = stream_name(stream)
|
119
|
+
result = connection.xpending(stream,
|
120
|
+
"#{stream}-#{group}",
|
121
|
+
message_id,
|
122
|
+
message_id,
|
123
|
+
1)
|
124
|
+
return 0 unless result.any?
|
125
|
+
|
126
|
+
result.first['count']
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Moves a message to the dead letter queue stream
|
131
|
+
def move_to_dlq(stream, group, message)
|
132
|
+
Nagare.logger.warn "Moving message to DLQ #{message} \
|
133
|
+
from stream #{stream}"
|
134
|
+
publish(Nagare::Config.dlq_stream, stream, message)
|
135
|
+
mark_processed(stream, group, message.first)
|
136
|
+
end
|
100
137
|
|
101
138
|
##
|
102
139
|
# Reads the next messages from the consumer group in redis.
|
data/lib/nagare/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nagare-redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Reis
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
126
|
requirements: []
|
127
|
-
rubygems_version: 3.0.3
|
127
|
+
rubygems_version: 3.0.3
|
128
128
|
signing_key:
|
129
129
|
specification_version: 4
|
130
130
|
summary: Persistent and resilient pub/sub using Redis Streams
|