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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0989adbcf8a099ac67362106e1724097f7266523a290a36d568d2f8d195a085a'
4
- data.tar.gz: da702aedd0055c0fb3ee4269999bc72009bc6d0823f68264770caa11c10c445c
3
+ metadata.gz: b061b1d275f3492d62c8ecfd64caaae755f9d9b60a0a4f7466ad72833788ea6b
4
+ data.tar.gz: df51d614f618b900c5cd432668d68bf1843ba74b4bf54a8ad39544812dd56ede
5
5
  SHA512:
6
- metadata.gz: 690db182773fca7bb41d230eb2a5a2c866f61eae733d1afd63b3f7b4693a747b0d1a82d169f7c09b745d70dd5e945e0c745eebb138e7c2405d608ccb736572ba
7
- data.tar.gz: 2f5bf0079b7932e15cf9996518d17ec9309882f601cef507a8952ebf22f4c9da01ba5ede9d77674bc491c2dbc6a04b6fb00d095e106075c9d2ad81a001421b49
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: 100, interval: 0.1)
13
+ def wait_for(attempts: 1000, interval: 0.1)
14
14
  attempts.times do
15
- break if yield
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(250))
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
- instance_variable_names.each_with_object({}) do |attribute_name, hash|
45
- attribute_name.sub!("@", "")
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
- lag_per_topic = @kafka_consumer.lag(@kafka_consumer.committed)
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",
@@ -1,3 +1,3 @@
1
1
  module NulogyMessageBusConsumer
2
- VERSION = "1.0.0"
2
+ VERSION = "2.0.1"
3
3
  end
@@ -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
@@ -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: 20_200_612_184_425) do
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"