nulogy_message_bus_consumer 1.0.0 → 2.0.1
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/Rakefile +0 -6
- data/lib/nulogy_message_bus_consumer/config.rb +2 -0
- data/lib/nulogy_message_bus_consumer/kafka_utils.rb +5 -4
- data/lib/nulogy_message_bus_consumer/message.rb +3 -3
- data/lib/nulogy_message_bus_consumer/steps/commit_on_success.rb +15 -0
- data/lib/nulogy_message_bus_consumer/steps/stream_messages_until_none_are_left.rb +9 -3
- data/lib/nulogy_message_bus_consumer/tasks/log_consumer_lag.rb +8 -2
- data/lib/nulogy_message_bus_consumer/version.rb +1 -1
- data/lib/nulogy_message_bus_consumer.rb +2 -2
- data/spec/dummy/db/schema.rb +1 -1
- data/spec/dummy/log/test.log +0 -7949
- data/spec/integration/nulogy_message_bus_consumer/end_to_end_spec.rb +54 -0
- data/spec/integration/nulogy_message_bus_consumer/kafka_utils_spec.rb +1 -1
- data/spec/integration/nulogy_message_bus_consumer/steps/commit_on_success_spec.rb +47 -39
- data/spec/integration/nulogy_message_bus_consumer/steps/connect_to_message_bus_spec.rb +12 -26
- data/spec/integration/test_topic_spec.rb +4 -0
- data/spec/support/kafka.rb +20 -12
- data/spec/support/test_topic.rb +1 -1
- data/spec/unit/nulogy_message_bus_consumer/steps/commit_on_success_spec.rb +7 -1
- metadata +7 -26
- data/config/credentials/message-bus-us-east-1.key +0 -1
- data/spec/dummy/config/credentials/message-bus-us-east-1.key +0 -1
- data/spec/dummy/log/development.log +0 -4
- data/spec/dummy/log/production.log +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b061b1d275f3492d62c8ecfd64caaae755f9d9b60a0a4f7466ad72833788ea6b
|
4
|
+
data.tar.gz: df51d614f618b900c5cd432668d68bf1843ba74b4bf54a8ad39544812dd56ede
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd39cb403d86779b3466f7b95ca1403adc6ed464c36c6270e6a37b5dca92117c0507ca3b9d1e4fb6632f737db57ebb2178cd484e65c163083e2ffab321d0775c
|
7
|
+
data.tar.gz: 8548a30f820e217a2bcfd1467d5967767649f096298c5fe6d5b407f6bc0da4aefd4a9170da9b9109b3621c7facc6bd3b9dcad03d5dcea337c3dd9443c4e61718
|
data/Rakefile
CHANGED
@@ -23,9 +23,3 @@ require "rspec/core/rake_task"
|
|
23
23
|
RSpec::Core::RakeTask.new(:spec)
|
24
24
|
require "standard/rake"
|
25
25
|
task default: %i[spec standard]
|
26
|
-
|
27
|
-
require "rake/release"
|
28
|
-
|
29
|
-
Rake::Release::Task.load_all do |spec|
|
30
|
-
spec.version_tag = "nulogy_message_bus_consumer-v#{spec.version}"
|
31
|
-
end
|
@@ -5,6 +5,7 @@ module NulogyMessageBusConsumer
|
|
5
5
|
:consumer_group_id,
|
6
6
|
:lag_check_interval_seconds,
|
7
7
|
:lag_checks,
|
8
|
+
:lag_timeout_milliseconds,
|
8
9
|
:log_lag_interval_seconds,
|
9
10
|
:prune_interval_seconds,
|
10
11
|
:prune_max_age,
|
@@ -14,6 +15,7 @@ module NulogyMessageBusConsumer
|
|
14
15
|
defaults = {
|
15
16
|
lag_check_interval_seconds: 20,
|
16
17
|
lag_checks: 6,
|
18
|
+
lag_timeout_milliseconds: 200,
|
17
19
|
log_lag_interval_seconds: 1.minute.to_i,
|
18
20
|
prune_interval_seconds: 1.hour.to_i,
|
19
21
|
prune_max_age: 8.days
|
@@ -10,17 +10,18 @@ module NulogyMessageBusConsumer
|
|
10
10
|
wait_for { consumer.assignment.empty? }
|
11
11
|
end
|
12
12
|
|
13
|
-
def wait_for(attempts:
|
13
|
+
def wait_for(attempts: 1000, interval: 0.1)
|
14
14
|
attempts.times do
|
15
|
-
|
15
|
+
return if yield
|
16
16
|
|
17
17
|
sleep interval
|
18
18
|
end
|
19
|
+
raise "wait_for timed out!"
|
19
20
|
end
|
20
21
|
|
21
|
-
def every_message_until_none_are_left(consumer)
|
22
|
+
def every_message_until_none_are_left(consumer, timeout = 250)
|
22
23
|
Enumerator.new do |yielder|
|
23
|
-
while (message = consumer.poll(
|
24
|
+
while (message = consumer.poll(timeout))
|
24
25
|
yielder.yield(message)
|
25
26
|
end
|
26
27
|
end
|
@@ -41,9 +41,9 @@ module NulogyMessageBusConsumer
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def to_h
|
44
|
-
|
45
|
-
attribute_name.
|
46
|
-
hash[attribute_name] = public_send(attribute_name)
|
44
|
+
instance_variables.each_with_object({}) do |instance_variable, hash|
|
45
|
+
attribute_name = instance_variable.to_s.delete("@")
|
46
|
+
hash[attribute_name.to_sym] = public_send(attribute_name)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module NulogyMessageBusConsumer
|
2
2
|
module Steps
|
3
3
|
class CommitOnSuccess
|
4
|
+
def initialize(logger)
|
5
|
+
@logger = logger
|
6
|
+
end
|
7
|
+
|
4
8
|
def call(kafka_consumer:, message:, **_)
|
5
9
|
result = yield
|
6
10
|
|
@@ -9,8 +13,18 @@ module NulogyMessageBusConsumer
|
|
9
13
|
if result == :success
|
10
14
|
kafka_consumer.store_offset(message)
|
11
15
|
kafka_consumer.commit
|
16
|
+
@logger.info(JSON.dump({
|
17
|
+
event: "message_committed",
|
18
|
+
kafka_message_id: message.id,
|
19
|
+
message: message.to_h
|
20
|
+
}))
|
12
21
|
else
|
13
22
|
reconnect_to_reprocess_same_message(kafka_consumer)
|
23
|
+
@logger.info(JSON.dump({
|
24
|
+
event: "message_failed",
|
25
|
+
kafka_message_id: message.id,
|
26
|
+
message: message.to_h
|
27
|
+
}))
|
14
28
|
end
|
15
29
|
|
16
30
|
result
|
@@ -22,6 +36,7 @@ module NulogyMessageBusConsumer
|
|
22
36
|
subscriptions = kafka_consumer.subscription
|
23
37
|
kafka_consumer.unsubscribe
|
24
38
|
kafka_consumer.subscribe(*subscriptions.to_h.keys)
|
39
|
+
KafkaUtils.wait_for_assignment(kafka_consumer)
|
25
40
|
end
|
26
41
|
|
27
42
|
def raise_if_invalid(result)
|
@@ -1,17 +1,23 @@
|
|
1
1
|
module NulogyMessageBusConsumer
|
2
2
|
module Steps
|
3
3
|
class StreamMessagesUntilNoneAreLeft
|
4
|
-
def initialize(logger)
|
4
|
+
def initialize(logger, timeout = 250)
|
5
5
|
@logger = logger
|
6
|
+
@timeout = timeout
|
6
7
|
end
|
7
8
|
|
8
9
|
def call(kafka_consumer:, **_)
|
9
|
-
KafkaUtils.every_message_until_none_are_left(kafka_consumer).each do |kafka_message|
|
10
|
-
yield(
|
10
|
+
KafkaUtils.every_message_until_none_are_left(kafka_consumer, @timeout).each do |kafka_message|
|
11
|
+
result = yield(
|
11
12
|
message: Message.from_kafka(kafka_message),
|
12
13
|
kafka_message: kafka_message
|
13
14
|
)
|
15
|
+
if result == :failure
|
16
|
+
# stop reading on failure or else we'll get stuck in a loop
|
17
|
+
return :failure
|
18
|
+
end
|
14
19
|
end
|
20
|
+
:success
|
15
21
|
rescue => e
|
16
22
|
@logger.error(JSON.dump({
|
17
23
|
event: "message_processing_errored",
|
@@ -3,9 +3,10 @@ module NulogyMessageBusConsumer
|
|
3
3
|
class LogConsumerLag
|
4
4
|
attr_reader :interval
|
5
5
|
|
6
|
-
def initialize(logger, interval_seconds)
|
6
|
+
def initialize(logger, interval_seconds, lag_timeout)
|
7
7
|
@logger = logger
|
8
8
|
@interval = interval_seconds
|
9
|
+
@lag_timeout = lag_timeout
|
9
10
|
end
|
10
11
|
|
11
12
|
def extract_args(kafka_consumer:, **_)
|
@@ -18,7 +19,12 @@ module NulogyMessageBusConsumer
|
|
18
19
|
# has finished connecting. There appears to be a race condition.
|
19
20
|
KafkaUtils.wait_for_assignment(@kafka_consumer)
|
20
21
|
|
21
|
-
|
22
|
+
# Note: consumer#committed has a timeout of 1200ms. To respect our lag_timeout, use the largest.
|
23
|
+
committed_timeout = [1200, @lag_timeout].max
|
24
|
+
# The first parameter is a TopicPartitionList. When nil, it uses all the assigned ones.
|
25
|
+
committed_offsets = @kafka_consumer.committed(nil, committed_timeout)
|
26
|
+
|
27
|
+
lag_per_topic = @kafka_consumer.lag(committed_offsets, @lag_timeout)
|
22
28
|
|
23
29
|
@logger.info(JSON.dump({
|
24
30
|
event: "consumer_lag",
|
@@ -52,7 +52,7 @@ module NulogyMessageBusConsumer
|
|
52
52
|
# be called once, without any messages.
|
53
53
|
Steps::ConnectToMessageBus.new(config, logger),
|
54
54
|
Steps::TimedTask.new(
|
55
|
-
Tasks::LogConsumerLag.new(logger, config.log_lag_interval_seconds)
|
55
|
+
Tasks::LogConsumerLag.new(logger, config.log_lag_interval_seconds, config.lag_timeout_milliseconds)
|
56
56
|
),
|
57
57
|
Steps::TimedTask.new(
|
58
58
|
Tasks::PruneProcessedMessages.new(logger, config.prune_interval_seconds, config.prune_max_age)
|
@@ -67,7 +67,7 @@ module NulogyMessageBusConsumer
|
|
67
67
|
Steps::StreamMessages.new(logger),
|
68
68
|
# Message processing steps start here.
|
69
69
|
Steps::LogMessages.new(logger),
|
70
|
-
Steps::CommitOnSuccess.new,
|
70
|
+
Steps::CommitOnSuccess.new(logger),
|
71
71
|
Steps::DeduplicateMessages.new(logger)
|
72
72
|
])
|
73
73
|
end
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
#
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema.define(version:
|
13
|
+
ActiveRecord::Schema.define(version: 2020_06_12_184425) do
|
14
14
|
# These are extensions that must be enabled in order to support this database
|
15
15
|
enable_extension "plpgsql"
|
16
16
|
enable_extension "uuid-ossp"
|