event_people 1.1.0 → 1.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/.event_people.yml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/event_people/broker/base.rb +3 -3
- data/lib/event_people/broker/context.rb +8 -0
- data/lib/event_people/broker/rabbit/queue.rb +43 -11
- data/lib/event_people/broker/rabbit/rabbit_context.rb +42 -5
- data/lib/event_people/broker/rabbit/retry_manager.rb +25 -0
- data/lib/event_people/broker/rabbit.rb +2 -2
- data/lib/event_people/config.rb +12 -0
- data/lib/event_people/event.rb +7 -2
- data/lib/event_people/listener.rb +9 -4
- data/lib/event_people/version.rb +1 -1
- data/lib/event_people.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ccaafb3d62e2c63881bfc08b080e4f129d79911a6f5d1a1e2aa3929a2b719bff
|
|
4
|
+
data.tar.gz: 889f25c2629daa9ee21a6c3621435ffc0eaae30c0ea9335bbf94da82eec126b8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b615ef14921b27781edc64e48bb637965e1fb91d99995ec231a0b731b5f21bcdb73c8001528646e051c52d1ab86c6f70a92c8250521b668d983bfb52a805adcc
|
|
7
|
+
data.tar.gz: 33628df7e0a91b4247724173e354117cb28f39e83bdd8bd0711df2265b632c183b8185c8fabdc290c24dcab4f55e085761a846720ab8b12fd89b4f90fd17da8f
|
data/.event_people.yml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
spec_version: "1.1.0"
|
|
2
|
-
implementation_version: "1.
|
|
2
|
+
implementation_version: "1.2.0"
|
|
3
3
|
language: ruby
|
|
4
4
|
package: "event_people (RubyGems)"
|
|
5
5
|
status: stable
|
|
@@ -19,9 +19,6 @@ implemented:
|
|
|
19
19
|
- RabbitContext
|
|
20
20
|
- Topic
|
|
21
21
|
- Queue
|
|
22
|
-
|
|
23
|
-
# Spec components not yet implemented (pending in spec too)
|
|
24
|
-
pending:
|
|
25
22
|
- RetryManager
|
|
26
23
|
- "Event.retryCount"
|
|
27
24
|
- "Event.incrementRetryCount"
|
|
@@ -36,6 +33,9 @@ pending:
|
|
|
36
33
|
- "RabbitContext.isLastRetry"
|
|
37
34
|
- "RabbitContext.dlqName"
|
|
38
35
|
|
|
36
|
+
# Spec components not yet implemented (pending in spec too)
|
|
37
|
+
pending: []
|
|
38
|
+
|
|
39
39
|
# Structural or naming departures from the spec
|
|
40
40
|
# (Ruby module-qualified class names are an accepted adaptation, not a deviation)
|
|
41
41
|
deviations: []
|
data/Gemfile.lock
CHANGED
|
@@ -15,13 +15,13 @@ module EventPeople
|
|
|
15
15
|
raise NotImplementedError.new('Must be implemented')
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def self.consume(event_name, &block)
|
|
18
|
+
def self.consume(event_name, retry_config: {}, &block)
|
|
19
19
|
consumers[event_name] ||= begin
|
|
20
|
-
new.consume(event_name, &block)
|
|
20
|
+
new.consume(event_name, retry_config: retry_config, &block)
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def consume(event_name, &block)
|
|
24
|
+
def consume(event_name, retry_config: {}, &block)
|
|
25
25
|
raise NotImplementedError.new('Must be implemented')
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -13,6 +13,14 @@ module EventPeople
|
|
|
13
13
|
raise NotImplementedError.new('Must be implemented')
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
def max_retries
|
|
17
|
+
raise NotImplementedError.new('Must be implemented')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def is_last_retry
|
|
21
|
+
raise NotImplementedError.new('Must be implemented')
|
|
22
|
+
end
|
|
23
|
+
|
|
16
24
|
def success!
|
|
17
25
|
warn '[DEPRECATED] EventPeople: `success!` is deprecated, use `success` instead. Will be removed in a future version.'
|
|
18
26
|
success
|
|
@@ -6,18 +6,21 @@ module EventPeople
|
|
|
6
6
|
@channel.prefetch(1)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def self.subscribe(channel, routing_key, &block)
|
|
10
|
-
new(channel).subscribe(routing_key, &block)
|
|
9
|
+
def self.subscribe(channel, routing_key, retry_config: {}, &block)
|
|
10
|
+
new(channel).subscribe(routing_key, retry_config: retry_config, &block)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def subscribe(routing_key, &block)
|
|
13
|
+
def subscribe(routing_key, retry_config: {}, &block)
|
|
14
14
|
base_name = routing_key.split('.')[0..2].join('.')
|
|
15
15
|
name = queue_name("#{base_name}.all")
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
declare_dlx_and_dlq
|
|
18
|
+
declare_retry_queue(name)
|
|
19
|
+
|
|
20
|
+
channel.queue(name, main_queue_options)
|
|
18
21
|
.bind(topic, routing_key: routing_key)
|
|
19
22
|
.subscribe(manual_ack: true) do |delivery_info, properties, payload|
|
|
20
|
-
callback(delivery_info, properties, payload, &block)
|
|
23
|
+
callback(delivery_info, properties, payload, name, retry_config, &block)
|
|
21
24
|
end
|
|
22
25
|
end
|
|
23
26
|
|
|
@@ -25,11 +28,37 @@ module EventPeople
|
|
|
25
28
|
|
|
26
29
|
attr_reader :channel
|
|
27
30
|
|
|
28
|
-
def
|
|
29
|
-
|
|
31
|
+
def declare_dlx_and_dlq
|
|
32
|
+
dlx_name = "#{EventPeople::Config::APP_NAME}_dlx"
|
|
33
|
+
dlq_name = "#{EventPeople::Config::APP_NAME}_dlq"
|
|
34
|
+
|
|
35
|
+
dlx = channel.fanout(dlx_name, durable: true)
|
|
36
|
+
channel.queue(dlq_name, durable: true).bind(dlx, routing_key: '')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def declare_retry_queue(main_queue_name)
|
|
40
|
+
channel.queue("#{main_queue_name}_retry", durable: true, arguments: {
|
|
41
|
+
'x-dead-letter-exchange' => '',
|
|
42
|
+
'x-dead-letter-routing-key' => main_queue_name
|
|
43
|
+
})
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def callback(delivery_info, properties, payload, queue_name, retry_config, &block)
|
|
47
|
+
event_name = delivery_info.routing_key
|
|
48
|
+
retry_count = [(properties.headers&.dig('x-event-people-retries') || 0).to_i, 0].max
|
|
49
|
+
|
|
50
|
+
event = EventPeople::Event.new(event_name, payload, 1.0, retry_count: retry_count)
|
|
30
51
|
|
|
31
|
-
|
|
32
|
-
|
|
52
|
+
context = EventPeople::Broker::Rabbit::RabbitContext.new(
|
|
53
|
+
channel,
|
|
54
|
+
delivery_info,
|
|
55
|
+
retry_count: retry_count,
|
|
56
|
+
max_retries: retry_config[:max_attempts],
|
|
57
|
+
delay_strategy: retry_config[:delay_strategy],
|
|
58
|
+
dlq_name: retry_config[:dlq_name],
|
|
59
|
+
queue_name: queue_name,
|
|
60
|
+
original_payload: payload
|
|
61
|
+
)
|
|
33
62
|
|
|
34
63
|
block.call(event, context)
|
|
35
64
|
end
|
|
@@ -38,8 +67,11 @@ module EventPeople
|
|
|
38
67
|
Rabbit::Topic.topic(channel)
|
|
39
68
|
end
|
|
40
69
|
|
|
41
|
-
def
|
|
42
|
-
{
|
|
70
|
+
def main_queue_options
|
|
71
|
+
{
|
|
72
|
+
durable: true,
|
|
73
|
+
arguments: { 'x-dead-letter-exchange' => "#{EventPeople::Config::APP_NAME}_dlx" }
|
|
74
|
+
}
|
|
43
75
|
end
|
|
44
76
|
|
|
45
77
|
def queue_name(routing_key)
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
module EventPeople
|
|
2
2
|
module Broker
|
|
3
3
|
class Rabbit::RabbitContext < EventPeople::Broker::Context
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
attr_reader :max_retries, :dlq_name
|
|
5
|
+
|
|
6
|
+
def initialize(channel, delivery_info, retry_count: 0, max_retries: nil, delay_strategy: nil, dlq_name: nil, queue_name: nil, original_payload: nil)
|
|
7
|
+
@channel = channel
|
|
8
|
+
@delivery_info = delivery_info
|
|
9
|
+
@retry_count = retry_count.to_i
|
|
10
|
+
@max_retries = (max_retries || EventPeople::Config::MAX_ATTEMPTS).to_i
|
|
11
|
+
@delay_strategy = delay_strategy || EventPeople::Config::DELAY_STRATEGY
|
|
12
|
+
@dlq_name = dlq_name || EventPeople::Config::DLQ_NAME
|
|
13
|
+
@queue_name = queue_name
|
|
14
|
+
@original_payload = original_payload
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def is_last_retry
|
|
18
|
+
@retry_count >= @max_retries - 1
|
|
7
19
|
end
|
|
8
20
|
|
|
9
21
|
def success
|
|
@@ -11,7 +23,32 @@ module EventPeople
|
|
|
11
23
|
end
|
|
12
24
|
|
|
13
25
|
def fail
|
|
14
|
-
|
|
26
|
+
retry_manager = Rabbit::RetryManager.new(@max_retries, @delay_strategy)
|
|
27
|
+
|
|
28
|
+
if retry_manager.should_retry?(@retry_count)
|
|
29
|
+
delay = retry_manager.get_next_delay(@retry_count)
|
|
30
|
+
begin
|
|
31
|
+
@channel.default_exchange.publish(
|
|
32
|
+
@original_payload,
|
|
33
|
+
routing_key: "#{@queue_name}_retry",
|
|
34
|
+
expiration: delay.to_s,
|
|
35
|
+
headers: { 'x-event-people-retries' => @retry_count + 1 }
|
|
36
|
+
)
|
|
37
|
+
@channel.ack(@delivery_info.delivery_tag, false)
|
|
38
|
+
rescue => e
|
|
39
|
+
# If publish+ack fails, nack so the message is redelivered from the main queue.
|
|
40
|
+
# This risks duplication if publish succeeded but ack failed, which is an inherent
|
|
41
|
+
# AMQP at-least-once limitation. We prefer redelivery over silent loss.
|
|
42
|
+
begin
|
|
43
|
+
@channel.nack(@delivery_info.delivery_tag, false, true)
|
|
44
|
+
rescue
|
|
45
|
+
# Channel may already be closed; nothing we can do.
|
|
46
|
+
end
|
|
47
|
+
raise e
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
@channel.nack(@delivery_info.delivery_tag, false, false)
|
|
51
|
+
end
|
|
15
52
|
end
|
|
16
53
|
|
|
17
54
|
def reject
|
|
@@ -19,4 +56,4 @@ module EventPeople
|
|
|
19
56
|
end
|
|
20
57
|
end
|
|
21
58
|
end
|
|
22
|
-
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module EventPeople
|
|
2
|
+
module Broker
|
|
3
|
+
class Rabbit::RetryManager
|
|
4
|
+
INITIAL_DELAY = (ENV['RABBIT_EVENT_PEOPLE_RETRY_TTL_MS'] || 1000).to_i
|
|
5
|
+
MAX_DELAY = 600_000
|
|
6
|
+
|
|
7
|
+
def initialize(max_attempts, delay_strategy = 'exponential')
|
|
8
|
+
@max_attempts = max_attempts
|
|
9
|
+
@delay_strategy = delay_strategy
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def should_retry?(retry_count)
|
|
13
|
+
retry_count < @max_attempts
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def get_next_delay(retry_count)
|
|
17
|
+
if @delay_strategy == 'fixed'
|
|
18
|
+
INITIAL_DELAY
|
|
19
|
+
else
|
|
20
|
+
[INITIAL_DELAY * (5**retry_count), MAX_DELAY].min
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -5,8 +5,8 @@ module EventPeople
|
|
|
5
5
|
@@connection ||= session
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
-
def consume(event_name, &block)
|
|
9
|
-
Queue.subscribe(channel, event_name, &block)
|
|
8
|
+
def consume(event_name, retry_config: {}, &block)
|
|
9
|
+
Queue.subscribe(channel, event_name, retry_config: retry_config, &block)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def produce(events)
|
data/lib/event_people/config.rb
CHANGED
|
@@ -6,8 +6,20 @@ module EventPeople
|
|
|
6
6
|
URL = ENV['RABBIT_URL']
|
|
7
7
|
FULL_URL = "#{ENV['RABBIT_URL']}/#{ENV['RABBIT_EVENT_PEOPLE_VHOST']}"
|
|
8
8
|
|
|
9
|
+
MAX_ATTEMPTS = (ENV['RABBIT_EVENT_PEOPLE_MAX_RETRIES'] || 3).to_i
|
|
10
|
+
DELAY_STRATEGY = 'exponential'
|
|
11
|
+
DLQ_NAME = "#{ENV['RABBIT_EVENT_PEOPLE_APP_NAME']}_dlq"
|
|
12
|
+
|
|
9
13
|
def self.broker
|
|
10
14
|
EventPeople::Broker::Rabbit
|
|
11
15
|
end
|
|
16
|
+
|
|
17
|
+
def self.get_retry_config
|
|
18
|
+
{
|
|
19
|
+
max_attempts: MAX_ATTEMPTS,
|
|
20
|
+
delay_strategy: DELAY_STRATEGY,
|
|
21
|
+
dlq_name: DLQ_NAME
|
|
22
|
+
}
|
|
23
|
+
end
|
|
12
24
|
end
|
|
13
25
|
end
|
data/lib/event_people/event.rb
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
module EventPeople
|
|
2
2
|
class Event
|
|
3
|
-
attr_reader :name, :headers, :body, :schema_version
|
|
3
|
+
attr_reader :name, :headers, :body, :schema_version, :retry_count
|
|
4
4
|
|
|
5
|
-
def initialize(name, body, schema_version = 1.0)
|
|
5
|
+
def initialize(name, body, schema_version = 1.0, retry_count: 0)
|
|
6
6
|
@name = name
|
|
7
7
|
@body = body.is_a?(String) ? JSON.parse(body) : body
|
|
8
8
|
@schema_version = @body&.dig('headers', 'schemaVersion') || schema_version
|
|
9
|
+
@retry_count = retry_count.to_i
|
|
9
10
|
|
|
10
11
|
if name?
|
|
11
12
|
generate_headers
|
|
@@ -15,6 +16,10 @@ module EventPeople
|
|
|
15
16
|
build_payload if @body&.key?('headers')
|
|
16
17
|
end
|
|
17
18
|
|
|
19
|
+
def increment_retry_count
|
|
20
|
+
@retry_count += 1
|
|
21
|
+
end
|
|
22
|
+
|
|
18
23
|
def payload
|
|
19
24
|
{ headers: headers, body: body }.to_json
|
|
20
25
|
end
|
|
@@ -2,16 +2,21 @@ require 'bunny'
|
|
|
2
2
|
|
|
3
3
|
module EventPeople
|
|
4
4
|
class Listener
|
|
5
|
-
def self.on(event_name, &block)
|
|
6
|
-
new.on(event_name, &block)
|
|
5
|
+
def self.on(event_name, max_attempts: nil, delay_strategy: nil, dlq_name: nil, &block)
|
|
6
|
+
new.on(event_name, max_attempts: max_attempts, delay_strategy: delay_strategy, dlq_name: dlq_name, &block)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def on(event_name, &block)
|
|
9
|
+
def on(event_name, max_attempts: nil, delay_strategy: nil, dlq_name: nil, &block)
|
|
10
10
|
raise(MissingAttributeError, 'Event name must be present') unless event_name&.size&.positive?
|
|
11
11
|
|
|
12
12
|
event_name = consumed_event_name(event_name)
|
|
13
13
|
|
|
14
|
-
EventPeople::Config.
|
|
14
|
+
retry_config = EventPeople::Config.get_retry_config
|
|
15
|
+
retry_config[:max_attempts] = max_attempts unless max_attempts.nil?
|
|
16
|
+
retry_config[:delay_strategy] = delay_strategy unless delay_strategy.nil?
|
|
17
|
+
retry_config[:dlq_name] = dlq_name unless dlq_name.nil?
|
|
18
|
+
|
|
19
|
+
EventPeople::Config.broker.consume(event_name, retry_config: retry_config, &block)
|
|
15
20
|
end
|
|
16
21
|
|
|
17
22
|
private
|
data/lib/event_people/version.rb
CHANGED
data/lib/event_people.rb
CHANGED
|
@@ -11,6 +11,7 @@ require 'event_people/broker/context'
|
|
|
11
11
|
require 'event_people/broker/rabbit'
|
|
12
12
|
require 'event_people/broker/rabbit/queue'
|
|
13
13
|
require 'event_people/broker/rabbit/rabbit_context'
|
|
14
|
+
require 'event_people/broker/rabbit/retry_manager'
|
|
14
15
|
require 'event_people/broker/rabbit/topic'
|
|
15
16
|
|
|
16
17
|
module EventPeople
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: event_people
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Pin People
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -109,6 +109,7 @@ files:
|
|
|
109
109
|
- lib/event_people/broker/rabbit.rb
|
|
110
110
|
- lib/event_people/broker/rabbit/queue.rb
|
|
111
111
|
- lib/event_people/broker/rabbit/rabbit_context.rb
|
|
112
|
+
- lib/event_people/broker/rabbit/retry_manager.rb
|
|
112
113
|
- lib/event_people/broker/rabbit/topic.rb
|
|
113
114
|
- lib/event_people/config.rb
|
|
114
115
|
- lib/event_people/daemon.rb
|