karafka 2.0.22 → 2.0.24
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/ci.yml +2 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +39 -1
- data/Gemfile.lock +9 -9
- data/README.md +3 -3
- data/config/{errors.yml → locales/errors.yml} +1 -1
- data/config/locales/pro_errors.yml +18 -0
- data/docker-compose.yml +3 -0
- data/karafka.gemspec +2 -3
- data/lib/karafka/active_job/job_options_contract.rb +1 -1
- data/lib/karafka/admin.rb +84 -6
- data/lib/karafka/app.rb +15 -4
- data/lib/karafka/base_consumer.rb +43 -1
- data/lib/karafka/connection/client.rb +4 -4
- data/lib/karafka/connection/listener.rb +1 -1
- data/lib/karafka/contracts/config.rb +1 -1
- data/lib/karafka/contracts/consumer_group.rb +1 -1
- data/lib/karafka/contracts/server_cli_options.rb +1 -1
- data/lib/karafka/contracts/topic.rb +1 -1
- data/lib/karafka/instrumentation/logger_listener.rb +32 -0
- data/lib/karafka/instrumentation/notifications.rb +3 -0
- data/lib/karafka/messages/message.rb +14 -2
- data/lib/karafka/messages/parser.rb +14 -0
- data/lib/karafka/pro/active_job/job_options_contract.rb +1 -1
- data/lib/karafka/pro/encryption/cipher.rb +58 -0
- data/lib/karafka/pro/encryption/contracts/config.rb +79 -0
- data/lib/karafka/pro/encryption/errors.rb +24 -0
- data/lib/karafka/pro/encryption/messages/middleware.rb +46 -0
- data/lib/karafka/pro/encryption/messages/parser.rb +56 -0
- data/lib/karafka/pro/encryption/setup/config.rb +48 -0
- data/lib/karafka/pro/encryption.rb +47 -0
- data/lib/karafka/pro/loader.rb +23 -2
- data/lib/karafka/pro/processing/strategies/aj_dlq_mom.rb +2 -2
- data/lib/karafka/pro/processing/strategies/aj_lrj_mom_vp.rb +2 -2
- data/lib/karafka/pro/processing/strategies/aj_mom_vp.rb +1 -1
- data/lib/karafka/pro/processing/strategies/default.rb +5 -1
- data/lib/karafka/pro/processing/strategies/dlq.rb +4 -2
- data/lib/karafka/pro/processing/strategies/dlq_lrj.rb +3 -1
- data/lib/karafka/pro/processing/strategies/dlq_lrj_mom.rb +1 -1
- data/lib/karafka/pro/processing/strategies/dlq_mom.rb +2 -2
- data/lib/karafka/pro/processing/strategies/lrj.rb +4 -2
- data/lib/karafka/pro/processing/strategies/lrj_mom.rb +2 -2
- data/lib/karafka/pro/processing/strategies/mom.rb +1 -1
- data/lib/karafka/pro/routing/features/dead_letter_queue/contract.rb +2 -2
- data/lib/karafka/pro/routing/features/long_running_job/contract.rb +2 -2
- data/lib/karafka/pro/routing/features/virtual_partitions/contract.rb +2 -2
- data/lib/karafka/processing/coordinator.rb +15 -0
- data/lib/karafka/processing/executor.rb +1 -1
- data/lib/karafka/processing/strategies/aj_dlq_mom.rb +2 -2
- data/lib/karafka/processing/strategies/default.rb +7 -1
- data/lib/karafka/processing/strategies/dlq.rb +4 -2
- data/lib/karafka/processing/strategies/dlq_mom.rb +2 -2
- data/lib/karafka/processing/strategies/mom.rb +1 -1
- data/lib/karafka/processing/worker.rb +1 -1
- data/lib/karafka/railtie.rb +3 -0
- data/lib/karafka/routing/builder.rb +1 -1
- data/lib/karafka/routing/consumer_group.rb +3 -3
- data/lib/karafka/routing/features/active_job/contract.rb +1 -1
- data/lib/karafka/routing/features/dead_letter_queue/contract.rb +1 -1
- data/lib/karafka/routing/features/manual_offset_management/contract.rb +1 -1
- data/lib/karafka/server.rb +14 -14
- data/lib/karafka/setup/config.rb +15 -2
- data/lib/karafka/status.rb +27 -9
- data/lib/karafka/templates/karafka.rb.erb +1 -2
- data/lib/karafka/time_trackers/pause.rb +3 -1
- data/lib/karafka/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +17 -23
- metadata.gz.sig +2 -4
- data/lib/karafka/instrumentation.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25eb837923f78f1bf35402bf24469228d8f5af12090b2d406718a0077ce42598
|
4
|
+
data.tar.gz: 23520ecab430080061046e683c0dcb47316d1216d1ad9843894caefff76e24cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e84c4c4dedd7a160ebcbd6cff53e0dfcf601a31eb19469d1a86eabb3f33507f3b1871c8f4489b743651118ed47e52925f12dba4fc67e462bd8be04d71dfa3bb
|
7
|
+
data.tar.gz: 8b9754f5566c5ef213c4803cfba2a4263553a5112e23fd12e42a963fd493f8f20c1409b12303628519ba7ef5bcf07aa09fabc6dd4ffc2a2114a6bad8f94cbc72
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.github/workflows/ci.yml
CHANGED
@@ -46,6 +46,7 @@ jobs:
|
|
46
46
|
run: \curl -sSL https://api.coditsu.io/run/ci | bash
|
47
47
|
|
48
48
|
specs:
|
49
|
+
timeout-minutes: 30
|
49
50
|
runs-on: ubuntu-latest
|
50
51
|
needs: diffend
|
51
52
|
strategy:
|
@@ -84,6 +85,7 @@ jobs:
|
|
84
85
|
run: bin/rspecs
|
85
86
|
|
86
87
|
integrations:
|
88
|
+
timeout-minutes: 30
|
87
89
|
runs-on: ubuntu-latest
|
88
90
|
needs: diffend
|
89
91
|
strategy:
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1.
|
1
|
+
3.1.3
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,43 @@
|
|
1
1
|
# Karafka framework changelog
|
2
2
|
|
3
|
+
## 2.0.24 (2022-12-19)
|
4
|
+
- **[Feature]** Provide out of the box encryption support for Pro.
|
5
|
+
- [Improvement] Add instrumentation upon `#pause`.
|
6
|
+
- [Improvement] Add instrumentation upon retries.
|
7
|
+
- [Improvement] Assign `#id` to consumers similar to other entities for ease of debugging.
|
8
|
+
- [Improvement] Add retries and pausing to the default `LoggerListener`.
|
9
|
+
- [Improvement] Introduce a new final `terminated` state that will kick in prior to exit but after all the instrumentation and other things are done.
|
10
|
+
- [Improvement] Ensure that state transitions are thread-safe and ensure state transitions can occur in one direction.
|
11
|
+
- [Improvement] Optimize status methods proxying to `Karafka::App`.
|
12
|
+
- [Improvement] Allow for easier state usage by introducing explicit `#to_s` for reporting.
|
13
|
+
- [Improvement] Change auto-generated id from `SecureRandom#uuid` to `SecureRandom#hex(6)`
|
14
|
+
- [Improvement] Emit statistic every 5 seconds by default.
|
15
|
+
- [Improvement] Introduce general messages parser that can be swapped when needed.
|
16
|
+
- [Fix] Do not trigger code reloading when `consumer_persistence` is enabled.
|
17
|
+
- [Fix] Shutdown producer after all the consumer components are down and the status is stopped. This will ensure, that any instrumentation related Kafka messaging can still operate.
|
18
|
+
|
19
|
+
### Upgrade notes
|
20
|
+
|
21
|
+
If you want to disable `librdkafka` statistics because you do not use them at all, update the `kafka` `statistics.interval.ms` setting and set it to `0`:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
class KarafkaApp < Karafka::App
|
25
|
+
setup do |config|
|
26
|
+
# Other settings...
|
27
|
+
config.kafka = {
|
28
|
+
'statistics.interval.ms': 0
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
## 2.0.23 (2022-12-07)
|
35
|
+
- [Maintenance] Align with `waterdrop` and `karafka-core`
|
36
|
+
- [Improvement] Provide `Admin#read_topic` API to get topic data without subscribing.
|
37
|
+
- [Improvement] Upon an end user `#pause`, do not commit the offset in automatic offset management mode. This will prevent from a scenario where pause is needed but during it a rebalance occurs and a different assigned process starts not from the pause location but from the automatic offset that may be different. This still allows for using the `#mark_as_consumed`.
|
38
|
+
- [Fix] Fix a scenario where manual `#pause` would be overwritten by a resume initiated by the strategy.
|
39
|
+
- [Fix] Fix a scenario where manual `#pause` in LRJ would cause infinite pause.
|
40
|
+
|
3
41
|
## 2.0.22 (2022-12-02)
|
4
42
|
- [Improvement] Load Pro components upon Karafka require so they can be altered prior to setup.
|
5
43
|
- [Improvement] Do not run LRJ jobs that were added to the jobs queue but were revoked meanwhile.
|
@@ -418,7 +456,7 @@ There are several things in the plan already for 2.1 and beyond, including a web
|
|
418
456
|
- Small integration specs refactoring + specs for pausing scenarios
|
419
457
|
|
420
458
|
## 2.0.0-alpha6 (2022-04-17)
|
421
|
-
- Fix a bug, where upon missing boot file and Rails, railtie would fail with a generic exception (#818)
|
459
|
+
- Fix a bug, where upon missing boot file and Rails, railtie would fail with a generic exception (#818)
|
422
460
|
- Fix an issue with parallel pristine specs colliding with each other during `bundle install` (#820)
|
423
461
|
- Replace `consumer.consume` with `consumer.consumed` event to match the behaviour
|
424
462
|
- Make sure, that offset committing happens before the `consumer.consumed` event is propagated
|
data/Gemfile.lock
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
karafka (2.0.
|
5
|
-
karafka-core (>= 2.0.
|
6
|
-
rdkafka (>= 0.12)
|
4
|
+
karafka (2.0.24)
|
5
|
+
karafka-core (>= 2.0.7, < 3.0.0)
|
7
6
|
thor (>= 0.20)
|
8
|
-
waterdrop (>= 2.4.
|
7
|
+
waterdrop (>= 2.4.7, < 3.0.0)
|
9
8
|
zeitwerk (~> 2.3)
|
10
9
|
|
11
10
|
GEM
|
@@ -30,8 +29,9 @@ GEM
|
|
30
29
|
activesupport (>= 5.0)
|
31
30
|
i18n (1.12.0)
|
32
31
|
concurrent-ruby (~> 1.0)
|
33
|
-
karafka-core (2.0.
|
32
|
+
karafka-core (2.0.7)
|
34
33
|
concurrent-ruby (>= 1.1)
|
34
|
+
rdkafka (>= 0.12)
|
35
35
|
mini_portile2 (2.8.0)
|
36
36
|
minitest (5.16.3)
|
37
37
|
rake (13.0.6)
|
@@ -48,7 +48,7 @@ GEM
|
|
48
48
|
rspec-expectations (3.12.0)
|
49
49
|
diff-lcs (>= 1.2.0, < 2.0)
|
50
50
|
rspec-support (~> 3.12.0)
|
51
|
-
rspec-mocks (3.12.
|
51
|
+
rspec-mocks (3.12.1)
|
52
52
|
diff-lcs (>= 1.2.0, < 2.0)
|
53
53
|
rspec-support (~> 3.12.0)
|
54
54
|
rspec-support (3.12.0)
|
@@ -61,13 +61,13 @@ GEM
|
|
61
61
|
thor (1.2.1)
|
62
62
|
tzinfo (2.0.5)
|
63
63
|
concurrent-ruby (~> 1.0)
|
64
|
-
waterdrop (2.4.
|
65
|
-
karafka-core (>= 2.0.
|
66
|
-
rdkafka (>= 0.10)
|
64
|
+
waterdrop (2.4.7)
|
65
|
+
karafka-core (>= 2.0.7, < 3.0.0)
|
67
66
|
zeitwerk (~> 2.3)
|
68
67
|
zeitwerk (2.6.6)
|
69
68
|
|
70
69
|
PLATFORMS
|
70
|
+
x86_64-darwin-21
|
71
71
|
x86_64-linux
|
72
72
|
|
73
73
|
DEPENDENCIES
|
data/README.md
CHANGED
@@ -72,10 +72,10 @@ Karafka.producer.produce_sync(topic: 'example', payload: { 'ping' => 'pong' }.to
|
|
72
72
|
```bash
|
73
73
|
bundle exec karafka server
|
74
74
|
|
75
|
-
[
|
76
|
-
[
|
75
|
+
[86d47f0b92f7] Polled 1 message in 1000ms
|
76
|
+
[3732873c8a74] Consume job for ExampleConsumer on example started
|
77
77
|
{"ping"=>"pong"}
|
78
|
-
[
|
78
|
+
[3732873c8a74] Consume job for ExampleConsumer on example finished in 0ms
|
79
79
|
```
|
80
80
|
|
81
81
|
## Want to Upgrade? LGPL is not for you? Want to help?
|
@@ -63,7 +63,7 @@ en:
|
|
63
63
|
|
64
64
|
pro_topic:
|
65
65
|
virtual_partitions.partitioner_respond_to_call: needs to be defined and needs to respond to `#call`
|
66
|
-
virtual_partitions.max_partitions_format: needs to be
|
66
|
+
virtual_partitions.max_partitions_format: needs to be equal or more than 1
|
67
67
|
manual_offset_management_not_with_virtual_partitions: cannot be used together with Virtual Partitions
|
68
68
|
long_running_job.active_format: needs to be either true or false
|
69
69
|
dead_letter_queue_not_with_virtual_partitions: cannot be used together with Virtual Partitions
|
@@ -0,0 +1,18 @@
|
|
1
|
+
en:
|
2
|
+
validations:
|
3
|
+
topic:
|
4
|
+
virtual_partitions.partitioner_respond_to_call: needs to be defined and needs to respond to `#call`
|
5
|
+
virtual_partitions.max_partitions_format: needs to be equal or more than 1
|
6
|
+
manual_offset_management_not_with_virtual_partitions: cannot be used together with Virtual Partitions
|
7
|
+
long_running_job.active_format: needs to be either true or false
|
8
|
+
dead_letter_queue_not_with_virtual_partitions: cannot be used together with Virtual Partitions
|
9
|
+
|
10
|
+
config:
|
11
|
+
encryption.active_format: 'needs to be either true or false'
|
12
|
+
encryption.public_key_invalid: 'is not a valid public RSA key'
|
13
|
+
encryption.public_key_needs_to_be_public: 'is a private RSA key not a public one'
|
14
|
+
encryption.private_keys_format: 'needs to be a hash of version and private key value'
|
15
|
+
encryption.private_keys_need_to_be_private: 'all keys need to be private'
|
16
|
+
encryption.version_format: must be a non-empty string
|
17
|
+
encryption.public_key_format: 'is not a valid public RSA key'
|
18
|
+
encryption.private_keys_invalid: 'contains an invalid private RSA key string'
|
data/docker-compose.yml
CHANGED
@@ -3,8 +3,10 @@ services:
|
|
3
3
|
zookeeper:
|
4
4
|
container_name: karafka_20_zookeeper
|
5
5
|
image: wurstmeister/zookeeper
|
6
|
+
restart: on-failure
|
6
7
|
ports:
|
7
8
|
- '2181:2181'
|
9
|
+
|
8
10
|
kafka:
|
9
11
|
container_name: karafka_20_kafka
|
10
12
|
image: wurstmeister/kafka
|
@@ -22,3 +24,4 @@ services:
|
|
22
24
|
benchmarks_00_10:10:1"
|
23
25
|
volumes:
|
24
26
|
- /var/run/docker.sock:/var/run/docker.sock
|
27
|
+
restart: on-failure
|
data/karafka.gemspec
CHANGED
@@ -21,10 +21,9 @@ Gem::Specification.new do |spec|
|
|
21
21
|
without having to focus on things that are not your business domain.
|
22
22
|
DESC
|
23
23
|
|
24
|
-
spec.add_dependency 'karafka-core', '>= 2.0.
|
25
|
-
spec.add_dependency 'rdkafka', '>= 0.12'
|
24
|
+
spec.add_dependency 'karafka-core', '>= 2.0.7', '< 3.0.0'
|
26
25
|
spec.add_dependency 'thor', '>= 0.20'
|
27
|
-
spec.add_dependency 'waterdrop', '>= 2.4.
|
26
|
+
spec.add_dependency 'waterdrop', '>= 2.4.7', '< 3.0.0'
|
28
27
|
spec.add_dependency 'zeitwerk', '~> 2.3'
|
29
28
|
|
30
29
|
spec.required_ruby_version = '>= 2.7.0'
|
@@ -10,7 +10,7 @@ module Karafka
|
|
10
10
|
configure do |config|
|
11
11
|
config.error_messages = YAML.safe_load(
|
12
12
|
File.read(
|
13
|
-
File.join(Karafka.gem_root, 'config', 'errors.yml')
|
13
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'errors.yml')
|
14
14
|
)
|
15
15
|
).fetch('en').fetch('validations').fetch('job_options')
|
16
16
|
end
|
data/lib/karafka/admin.rb
CHANGED
@@ -9,7 +9,70 @@ module Karafka
|
|
9
9
|
# @note It always uses the primary defined cluster and does not support multi-cluster work.
|
10
10
|
# If you need this, just replace the cluster info for the time you use this
|
11
11
|
module Admin
|
12
|
+
# A fake admin topic representation that we use for messages fetched using this API
|
13
|
+
# We cannot use the topics directly because we may want to request data from topics that we
|
14
|
+
# do not have in the routing
|
15
|
+
Topic = Struct.new(:name, :deserializer)
|
16
|
+
|
17
|
+
# Defaults for config
|
18
|
+
CONFIG_DEFAULTS = {
|
19
|
+
'group.id': 'karafka_admin',
|
20
|
+
# We want to know when there is no more data not to end up with an endless loop
|
21
|
+
'enable.partition.eof': true,
|
22
|
+
'statistics.interval.ms': 0
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
private_constant :Topic, :CONFIG_DEFAULTS
|
26
|
+
|
12
27
|
class << self
|
28
|
+
# Allows us to read messages from the topic
|
29
|
+
#
|
30
|
+
# @param name [String, Symbol] topic name
|
31
|
+
# @param partition [Integer] partition
|
32
|
+
# @param count [Integer] how many messages we want to get at most
|
33
|
+
# @param offset [Integer] offset from which we should start. If -1 is provided (default) we
|
34
|
+
# will start from the latest offset
|
35
|
+
#
|
36
|
+
# @return [Array<Karafka::Messages::Message>] array with messages
|
37
|
+
def read_topic(name, partition, count, offset = -1)
|
38
|
+
messages = []
|
39
|
+
tpl = Rdkafka::Consumer::TopicPartitionList.new
|
40
|
+
|
41
|
+
with_consumer do |consumer|
|
42
|
+
if offset.negative?
|
43
|
+
offsets = consumer.query_watermark_offsets(name, partition)
|
44
|
+
offset = offsets.last - count
|
45
|
+
end
|
46
|
+
|
47
|
+
offset = offset.negative? ? 0 : offset
|
48
|
+
|
49
|
+
tpl.add_topic_and_partitions_with_offsets(name, partition => offset)
|
50
|
+
consumer.assign(tpl)
|
51
|
+
|
52
|
+
# We should poll as long as we don't have all the messages that we need or as long as
|
53
|
+
# we do not read all the messages from the topic
|
54
|
+
loop do
|
55
|
+
break if messages.size >= count
|
56
|
+
|
57
|
+
message = consumer.poll(200)
|
58
|
+
messages << message if message
|
59
|
+
rescue Rdkafka::RdkafkaError => e
|
60
|
+
# End of partition
|
61
|
+
break if e.code == :partition_eof
|
62
|
+
|
63
|
+
raise e
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
messages.map do |message|
|
68
|
+
Messages::Builders::Message.call(
|
69
|
+
message,
|
70
|
+
Topic.new(name, Karafka::App.config.deserializer),
|
71
|
+
Time.now
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
13
76
|
# Creates Kafka topic with given settings
|
14
77
|
#
|
15
78
|
# @param name [String] topic name
|
@@ -52,15 +115,30 @@ module Karafka
|
|
52
115
|
|
53
116
|
# Creates admin instance and yields it. After usage it closes the admin instance
|
54
117
|
def with_admin
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
admin = ::Rdkafka::Config.new(config).admin
|
59
|
-
result = yield(admin)
|
60
|
-
result
|
118
|
+
admin = config(:producer).admin
|
119
|
+
yield(admin)
|
61
120
|
ensure
|
62
121
|
admin&.close
|
63
122
|
end
|
123
|
+
|
124
|
+
# Creates consumer instance and yields it. After usage it closes the consumer instance
|
125
|
+
def with_consumer
|
126
|
+
consumer = config(:consumer).consumer
|
127
|
+
yield(consumer)
|
128
|
+
ensure
|
129
|
+
consumer&.close
|
130
|
+
end
|
131
|
+
|
132
|
+
# @param type [Symbol] type of config we want
|
133
|
+
# @return [::Rdkafka::Config] rdkafka config
|
134
|
+
def config(type)
|
135
|
+
config_hash = Karafka::Setup::AttributesMap.public_send(
|
136
|
+
type,
|
137
|
+
Karafka::App.config.kafka.dup.merge(CONFIG_DEFAULTS)
|
138
|
+
)
|
139
|
+
|
140
|
+
::Rdkafka::Config.new(config_hash)
|
141
|
+
end
|
64
142
|
end
|
65
143
|
end
|
66
144
|
end
|
data/lib/karafka/app.rb
CHANGED
@@ -35,10 +35,21 @@ module Karafka
|
|
35
35
|
# Just a nicer name for the consumer groups
|
36
36
|
alias routes consumer_groups
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
# Allow for easier status management via `Karafka::App` by aliasing status methods here
|
39
|
+
Status::STATES.each do |state, transition|
|
40
|
+
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
41
|
+
def #{state}
|
42
|
+
App.config.internal.status.#{state}
|
43
|
+
end
|
44
|
+
|
45
|
+
def #{state}?
|
46
|
+
App.config.internal.status.#{state}?
|
47
|
+
end
|
48
|
+
|
49
|
+
def #{transition}
|
50
|
+
App.config.internal.status.#{transition}
|
51
|
+
end
|
52
|
+
RUBY
|
42
53
|
end
|
43
54
|
|
44
55
|
# Methods that should be delegated to Karafka module
|
@@ -4,6 +4,8 @@
|
|
4
4
|
module Karafka
|
5
5
|
# Base consumer from which all Karafka consumers should inherit
|
6
6
|
class BaseConsumer
|
7
|
+
# @return [String] id of the current consumer
|
8
|
+
attr_reader :id
|
7
9
|
# @return [Karafka::Routing::Topic] topic to which a given consumer is subscribed
|
8
10
|
attr_accessor :topic
|
9
11
|
# @return [Karafka::Messages::Messages] current messages batch
|
@@ -15,6 +17,11 @@ module Karafka
|
|
15
17
|
# @return [Waterdrop::Producer] producer instance
|
16
18
|
attr_accessor :producer
|
17
19
|
|
20
|
+
# Creates new consumer and assigns it an id
|
21
|
+
def initialize
|
22
|
+
@id = SecureRandom.hex(6)
|
23
|
+
end
|
24
|
+
|
18
25
|
# Can be used to run preparation code prior to the job being enqueued
|
19
26
|
#
|
20
27
|
# @private
|
@@ -190,7 +197,10 @@ module Karafka
|
|
190
197
|
# @param offset [Integer] offset from which we want to restart the processing
|
191
198
|
# @param timeout [Integer, nil] how long in milliseconds do we want to pause or nil to use the
|
192
199
|
# default exponential pausing strategy defined for retries
|
193
|
-
|
200
|
+
# @param manual_pause [Boolean] Flag to differentiate between user pause and system/strategy
|
201
|
+
# based pause. While they both pause in exactly the same way, the strategy application
|
202
|
+
# may need to differentiate between them.
|
203
|
+
def pause(offset, timeout = nil, manual_pause = true)
|
194
204
|
timeout ? coordinator.pause_tracker.pause(timeout) : coordinator.pause_tracker.pause
|
195
205
|
|
196
206
|
client.pause(
|
@@ -198,6 +208,20 @@ module Karafka
|
|
198
208
|
messages.metadata.partition,
|
199
209
|
offset
|
200
210
|
)
|
211
|
+
|
212
|
+
# Indicate, that user took a manual action of pausing
|
213
|
+
coordinator.manual_pause if manual_pause
|
214
|
+
|
215
|
+
Karafka.monitor.instrument(
|
216
|
+
'consumer.consuming.pause',
|
217
|
+
caller: self,
|
218
|
+
manual: manual_pause,
|
219
|
+
topic: messages.metadata.topic,
|
220
|
+
partition: messages.metadata.partition,
|
221
|
+
offset: offset,
|
222
|
+
timeout: coordinator.pause_tracker.current_timeout,
|
223
|
+
attempt: coordinator.pause_tracker.attempt
|
224
|
+
)
|
201
225
|
end
|
202
226
|
|
203
227
|
# Resumes processing of the current topic partition
|
@@ -226,5 +250,23 @@ module Karafka
|
|
226
250
|
def revoked?
|
227
251
|
coordinator.revoked?
|
228
252
|
end
|
253
|
+
|
254
|
+
# Pauses the processing from the last offset to retry on given message
|
255
|
+
# @private
|
256
|
+
def retry_after_pause
|
257
|
+
pause(coordinator.seek_offset, nil, false)
|
258
|
+
|
259
|
+
# Instrumentation needs to run **after** `#pause` invocation because we rely on the states
|
260
|
+
# set by `#pause`
|
261
|
+
Karafka.monitor.instrument(
|
262
|
+
'consumer.consuming.retry',
|
263
|
+
caller: self,
|
264
|
+
topic: messages.metadata.topic,
|
265
|
+
partition: messages.metadata.partition,
|
266
|
+
offset: coordinator.seek_offset,
|
267
|
+
timeout: coordinator.pause_tracker.current_timeout,
|
268
|
+
attempt: coordinator.pause_tracker.attempt
|
269
|
+
)
|
270
|
+
end
|
229
271
|
end
|
230
272
|
end
|
@@ -308,8 +308,8 @@ module Karafka
|
|
308
308
|
@closed = true
|
309
309
|
|
310
310
|
# Remove callbacks runners that were registered
|
311
|
-
::Karafka::Instrumentation.statistics_callbacks.delete(@subscription_group.id)
|
312
|
-
::Karafka::Instrumentation.error_callbacks.delete(@subscription_group.id)
|
311
|
+
::Karafka::Core::Instrumentation.statistics_callbacks.delete(@subscription_group.id)
|
312
|
+
::Karafka::Core::Instrumentation.error_callbacks.delete(@subscription_group.id)
|
313
313
|
|
314
314
|
@kafka.close
|
315
315
|
@buffer.clear
|
@@ -397,7 +397,7 @@ module Karafka
|
|
397
397
|
@name = consumer.name
|
398
398
|
|
399
399
|
# Register statistics runner for this particular type of callbacks
|
400
|
-
::Karafka::Instrumentation.statistics_callbacks.add(
|
400
|
+
::Karafka::Core::Instrumentation.statistics_callbacks.add(
|
401
401
|
@subscription_group.id,
|
402
402
|
Instrumentation::Callbacks::Statistics.new(
|
403
403
|
@subscription_group.id,
|
@@ -408,7 +408,7 @@ module Karafka
|
|
408
408
|
)
|
409
409
|
|
410
410
|
# Register error tracking callback
|
411
|
-
::Karafka::Instrumentation.error_callbacks.add(
|
411
|
+
::Karafka::Core::Instrumentation.error_callbacks.add(
|
412
412
|
@subscription_group.id,
|
413
413
|
Instrumentation::Callbacks::Error.new(
|
414
414
|
@subscription_group.id,
|
@@ -21,7 +21,7 @@ module Karafka
|
|
21
21
|
def initialize(consumer_group_coordinator, subscription_group, jobs_queue)
|
22
22
|
proc_config = ::Karafka::App.config.internal.processing
|
23
23
|
|
24
|
-
@id = SecureRandom.
|
24
|
+
@id = SecureRandom.hex(6)
|
25
25
|
@consumer_group_coordinator = consumer_group_coordinator
|
26
26
|
@subscription_group = subscription_group
|
27
27
|
@jobs_queue = jobs_queue
|
@@ -12,7 +12,7 @@ module Karafka
|
|
12
12
|
configure do |config|
|
13
13
|
config.error_messages = YAML.safe_load(
|
14
14
|
File.read(
|
15
|
-
File.join(Karafka.gem_root, 'config', 'errors.yml')
|
15
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'errors.yml')
|
16
16
|
)
|
17
17
|
).fetch('en').fetch('validations').fetch('config')
|
18
18
|
end
|
@@ -7,7 +7,7 @@ module Karafka
|
|
7
7
|
configure do |config|
|
8
8
|
config.error_messages = YAML.safe_load(
|
9
9
|
File.read(
|
10
|
-
File.join(Karafka.gem_root, 'config', 'errors.yml')
|
10
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'errors.yml')
|
11
11
|
)
|
12
12
|
).fetch('en').fetch('validations').fetch('consumer_group')
|
13
13
|
end
|
@@ -7,7 +7,7 @@ module Karafka
|
|
7
7
|
configure do |config|
|
8
8
|
config.error_messages = YAML.safe_load(
|
9
9
|
File.read(
|
10
|
-
File.join(Karafka.gem_root, 'config', 'errors.yml')
|
10
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'errors.yml')
|
11
11
|
)
|
12
12
|
).fetch('en').fetch('validations').fetch('server_cli_options')
|
13
13
|
end
|
@@ -7,7 +7,7 @@ module Karafka
|
|
7
7
|
configure do |config|
|
8
8
|
config.error_messages = YAML.safe_load(
|
9
9
|
File.read(
|
10
|
-
File.join(Karafka.gem_root, 'config', 'errors.yml')
|
10
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'errors.yml')
|
11
11
|
)
|
12
12
|
).fetch('en').fetch('validations').fetch('topic')
|
13
13
|
end
|
@@ -63,6 +63,38 @@ module Karafka
|
|
63
63
|
info "[#{job.id}] #{job_type} job for #{consumer} on #{topic} finished in #{time}ms"
|
64
64
|
end
|
65
65
|
|
66
|
+
# Prints info about a pause occurrence. Irrelevant if user or system initiated.
|
67
|
+
#
|
68
|
+
# @param event [Karafka::Core::Monitoring::Event] event details including payload
|
69
|
+
def on_consumer_consuming_pause(event)
|
70
|
+
topic = event[:topic]
|
71
|
+
partition = event[:partition]
|
72
|
+
offset = event[:offset]
|
73
|
+
consumer = event[:caller]
|
74
|
+
timeout = event[:timeout]
|
75
|
+
|
76
|
+
info <<~MSG.tr("\n", ' ').strip!
|
77
|
+
[#{consumer.id}] Pausing partition #{partition} of topic #{topic}
|
78
|
+
on offset #{offset} for #{timeout} ms.
|
79
|
+
MSG
|
80
|
+
end
|
81
|
+
|
82
|
+
# Prints info about retry of processing after an error
|
83
|
+
#
|
84
|
+
# @param event [Karafka::Core::Monitoring::Event] event details including payload
|
85
|
+
def on_consumer_consuming_retry(event)
|
86
|
+
topic = event[:topic]
|
87
|
+
partition = event[:partition]
|
88
|
+
offset = event[:offset]
|
89
|
+
consumer = event[:caller]
|
90
|
+
timeout = event[:timeout]
|
91
|
+
|
92
|
+
info <<~MSG.tr("\n", ' ').strip!
|
93
|
+
[#{consumer.id}] Retrying of #{consumer.class} after #{timeout} ms
|
94
|
+
on partition #{partition} of topic #{topic} from offset #{offset}
|
95
|
+
MSG
|
96
|
+
end
|
97
|
+
|
66
98
|
# Logs info about system signals that Karafka received and prints backtrace for threads in
|
67
99
|
# case of ttin
|
68
100
|
#
|
@@ -9,7 +9,19 @@ module Karafka
|
|
9
9
|
class Message
|
10
10
|
extend Forwardable
|
11
11
|
|
12
|
-
|
12
|
+
class << self
|
13
|
+
# @return [Object] general parser
|
14
|
+
# @note We cache it here for performance reasons. It is 2.5x times faster than getting it
|
15
|
+
# via the config chain.
|
16
|
+
def parser
|
17
|
+
@parser ||= App.config.internal.messages.parser
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :metadata
|
22
|
+
# raw payload needs to be mutable as we want to have option to change it in the parser
|
23
|
+
# prior to the final deserialization
|
24
|
+
attr_accessor :raw_payload
|
13
25
|
|
14
26
|
def_delegators :metadata, *Metadata.members
|
15
27
|
|
@@ -42,7 +54,7 @@ module Karafka
|
|
42
54
|
|
43
55
|
# @return [Object] deserialized data
|
44
56
|
def deserialize
|
45
|
-
|
57
|
+
self.class.parser.call(self)
|
46
58
|
end
|
47
59
|
end
|
48
60
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
module Messages
|
5
|
+
# Default message parser. The only thing it does, is calling the deserializer
|
6
|
+
class Parser
|
7
|
+
# @param message [::Karafka::Messages::Message]
|
8
|
+
# @return [Object] deserialized payload
|
9
|
+
def call(message)
|
10
|
+
message.metadata.deserializer.call(message)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -20,7 +20,7 @@ module Karafka
|
|
20
20
|
configure do |config|
|
21
21
|
config.error_messages = YAML.safe_load(
|
22
22
|
File.read(
|
23
|
-
File.join(Karafka.gem_root, 'config', 'errors.yml')
|
23
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'errors.yml')
|
24
24
|
)
|
25
25
|
).fetch('en').fetch('validations').fetch('job_options')
|
26
26
|
end
|