nulogy_message_bus_consumer 1.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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"