karafka 2.5.0.beta2 → 2.5.0.rc2
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/.github/workflows/ci.yml +5 -5
- data/.github/workflows/push.yml +2 -3
- data/CHANGELOG.md +16 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +20 -20
- data/bin/integrations +1 -0
- data/config/locales/errors.yml +2 -1
- data/docker-compose.yml +1 -1
- data/examples/payloads/avro/.gitkeep +0 -0
- data/karafka.gemspec +2 -2
- data/lib/karafka/active_job/job_extensions.rb +4 -1
- data/lib/karafka/admin.rb +27 -15
- data/lib/karafka/connection/client.rb +9 -0
- data/lib/karafka/connection/proxy.rb +1 -1
- data/lib/karafka/contracts/base.rb +3 -2
- data/lib/karafka/contracts/config.rb +2 -1
- data/lib/karafka/helpers/interval_runner.rb +8 -0
- data/lib/karafka/instrumentation/logger_listener.rb +11 -11
- data/lib/karafka/instrumentation/vendors/kubernetes/base_listener.rb +17 -2
- data/lib/karafka/instrumentation/vendors/kubernetes/liveness_listener.rb +29 -6
- data/lib/karafka/instrumentation/vendors/kubernetes/swarm_liveness_listener.rb +9 -0
- data/lib/karafka/pro/encryption.rb +4 -1
- data/lib/karafka/pro/processing/coordinators/errors_tracker.rb +5 -0
- data/lib/karafka/pro/processing/strategies/dlq/default.rb +4 -3
- data/lib/karafka/pro/recurring_tasks.rb +8 -2
- data/lib/karafka/pro/routing/features/swarm/contracts/routing.rb +3 -2
- data/lib/karafka/pro/routing/features/swarm.rb +4 -1
- data/lib/karafka/pro/scheduled_messages/consumer.rb +45 -8
- data/lib/karafka/pro/scheduled_messages/dispatcher.rb +2 -1
- data/lib/karafka/pro/scheduled_messages/proxy.rb +15 -3
- data/lib/karafka/pro/scheduled_messages/serializer.rb +2 -4
- data/lib/karafka/pro/scheduled_messages/state.rb +20 -23
- data/lib/karafka/pro/scheduled_messages/tracker.rb +34 -8
- data/lib/karafka/pro/scheduled_messages.rb +4 -1
- data/lib/karafka/routing/builder.rb +12 -3
- data/lib/karafka/routing/features/base/expander.rb +8 -2
- data/lib/karafka/server.rb +4 -1
- data/lib/karafka/setup/config.rb +17 -5
- data/lib/karafka/swarm/supervisor.rb +5 -2
- data/lib/karafka/version.rb +1 -1
- metadata +10 -9
- /data/examples/payloads/json/{enrollment_event.json → sample_set_01/enrollment_event.json} +0 -0
- /data/examples/payloads/json/{ingestion_event.json → sample_set_01/ingestion_event.json} +0 -0
- /data/examples/payloads/json/{transaction_event.json → sample_set_01/transaction_event.json} +0 -0
- /data/examples/payloads/json/{user_event.json → sample_set_01/user_event.json} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45fa2a9d2f2e68cdf611a2610d339d1c33bfdfa42570dccf817950279c1678bc
|
4
|
+
data.tar.gz: 32abcc95bda1e13d6d6dc76b25f278867ed055a39f1af675a28efd5cd79d83f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54c9455fc69ae7f0ab4593be64f0c337680aa3894484a846d07dd9c6aa7e797db901c2a907d11b25088d62e8411e973ae27d39ebb627d5e2cd2f8bbc0f061d73
|
7
|
+
data.tar.gz: 2649ac38264e56c88c6608eb36c7dadcf3d6b0020f7ae5ce9ed27ff6c74fcbe95e3f9051fb3c1968508e8d21784d7a54007756f42a153c108ed5fb009f35f58c
|
data/.github/workflows/ci.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
name:
|
1
|
+
name: CI
|
2
2
|
|
3
3
|
concurrency:
|
4
4
|
group: ${{ github.workflow }}-${{ github.ref }}
|
@@ -31,7 +31,7 @@ jobs:
|
|
31
31
|
fetch-depth: 0
|
32
32
|
|
33
33
|
- name: Set up Ruby
|
34
|
-
uses: ruby/setup-ruby@
|
34
|
+
uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
|
35
35
|
with:
|
36
36
|
ruby-version: 3.4
|
37
37
|
bundler-cache: true
|
@@ -118,7 +118,7 @@ jobs:
|
|
118
118
|
run: rm -f Gemfile.lock
|
119
119
|
|
120
120
|
- name: Set up Ruby
|
121
|
-
uses: ruby/setup-ruby@
|
121
|
+
uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
|
122
122
|
with:
|
123
123
|
ruby-version: ${{matrix.ruby}}
|
124
124
|
bundler-cache: true
|
@@ -164,7 +164,7 @@ jobs:
|
|
164
164
|
docker compose up -d || (sleep 5 && docker compose up -d)
|
165
165
|
|
166
166
|
- name: Set up Ruby
|
167
|
-
uses: ruby/setup-ruby@
|
167
|
+
uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
|
168
168
|
with:
|
169
169
|
# Do not use cache here as we run bundle install also later in some of the integration
|
170
170
|
# tests and we need to be able to run it without cache
|
@@ -228,7 +228,7 @@ jobs:
|
|
228
228
|
docker compose up -d || (sleep 5 && docker compose up -d)
|
229
229
|
|
230
230
|
- name: Set up Ruby
|
231
|
-
uses: ruby/setup-ruby@
|
231
|
+
uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
|
232
232
|
with:
|
233
233
|
ruby-version: ${{matrix.ruby}}
|
234
234
|
bundler: 'latest'
|
data/.github/workflows/push.yml
CHANGED
@@ -24,7 +24,7 @@ jobs:
|
|
24
24
|
fetch-depth: 0
|
25
25
|
|
26
26
|
- name: Set up Ruby
|
27
|
-
uses: ruby/setup-ruby@
|
27
|
+
uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
|
28
28
|
with:
|
29
29
|
bundler-cache: false
|
30
30
|
|
@@ -32,5 +32,4 @@ jobs:
|
|
32
32
|
run: |
|
33
33
|
bundle install --jobs 4 --retry 3
|
34
34
|
|
35
|
-
#
|
36
|
-
- uses: rubygems/release-gem@9e85cb11501bebc2ae661c1500176316d3987059 # v1
|
35
|
+
- uses: rubygems/release-gem@a25424ba2ba8b387abc8ef40807c2c85b96cbe32 # v1.1.1
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
# Karafka Framework Changelog
|
2
2
|
|
3
3
|
## 2.5.0 (Unreleased)
|
4
|
+
- **[Breaking]** Change how consistency of DLQ dispatches works in Pro (`partition_key` vs. direct partition id mapping).
|
5
|
+
- **[Breaking]** Remove the headers `source_key` from the Pro DLQ dispatched messages as the original key is now fully preserved.
|
4
6
|
- **[Breaking]** Use DLQ and Piping prefix `source_` instead of `original_` to align with naming convention of Kafka Streams and Apache Flink for future usage.
|
5
7
|
- **[Breaking]** Rename scheduled jobs topics names in their config (Pro).
|
8
|
+
- **[Breaking]** Change K8s listener response from `204` to `200` and include JSON body with reasons.
|
9
|
+
- **[Breaking]** Replace admin config `max_attempts` with `max_retries_duration` and
|
6
10
|
- **[Feature]** Parallel Segments for concurrent processing of the same partition with more than partition count of processes (Pro).
|
11
|
+
- [Enhancement] Normalize topic + partition logs format.
|
7
12
|
- [Enhancement] Support KIP-82 (header values of arrays).
|
8
13
|
- [Enhancement] Enhance errors tracker with `#counts` that contains per-error class specific counters for granular flow handling.
|
9
14
|
- [Enhancement] Provide explicit `Karafka::Admin.copy_consumer_group` API.
|
@@ -35,12 +40,19 @@
|
|
35
40
|
- [Enhancement] Execute the help CLI command when no command provided (similar to Rails) to improve DX.
|
36
41
|
- [Enhancement] Remove backtrace from the CLI error for incorrect commands (similar to Rails) to improve DX.
|
37
42
|
- [Enhancement] Provide `karafka topics help` sub-help due to nesting of Declarative Topics actions.
|
43
|
+
- [Enhancement] Use independent keys for different states of reporting in scheduled messages.
|
44
|
+
- [Enhancement] Enrich scheduled messages state reporter with debug data.
|
45
|
+
- [Enhancement] Introduce a new state called `stopped` to the scheduled messages.
|
46
|
+
- [Enhancement] Do not overwrite the `key` in the Pro DLQ dispatched messages for routing reasons.
|
47
|
+
- [Enhancement] Introduce `errors_tracker.trace_id` for distributed error details correlation with the Web UI.
|
48
|
+
- [Enhancement] Improve contracts validations reporting.
|
49
|
+
- [Enhancement] Optimize topic creation and repartitioning admin operations for topics with hundreds of partitions.
|
38
50
|
- [Refactor] Introduce a `bin/verify_kafka_warnings` script to clean Kafka from temporary test-suite topics.
|
39
51
|
- [Refactor] Introduce a `bin/verify_topics_naming` script to ensure proper test topics naming convention.
|
40
52
|
- [Refactor] Make sure all temporary topics have a `it-` prefix in their name.
|
41
53
|
- [Refactor] Improve CI specs parallelization.
|
42
54
|
- [Maintenance] Lower the `Karafka::Admin` `poll_timeout` to 50 ms to improve responsiveness of admin operations.
|
43
|
-
- [Maintenance] Require `karafka-rdkafka` `>=` `0.19.
|
55
|
+
- [Maintenance] Require `karafka-rdkafka` `>=` `0.19.5` due to usage of `#rd_kafka_global_init`, KIP-82, new producer caching engine and improvements to the `partition_key` assignments.
|
44
56
|
- [Maintenance] Add Deimos routing patch into integration suite not to break it in the future.
|
45
57
|
- [Maintenance] Remove Rails `7.0` specs due to upcoming EOL.
|
46
58
|
- [Fix] Fix Recurring Tasks and Scheduled Messages not working with Swarm (using closed producer).
|
@@ -58,6 +70,9 @@
|
|
58
70
|
- [Fix] `karafka` cannot be required without Bundler.
|
59
71
|
- [Fix] Scheduled Messages re-seek moves to `latest` on inheritance of initial offset when `0` offset is compacted.
|
60
72
|
- [Fix] Seek to `:latest` without `topic_partition_position` (-1) will not seek at all.
|
73
|
+
- [Fix] Extremely high turn over of scheduled messages can cause them not to reach EOF/Loaded state.
|
74
|
+
- [Fix] Fix incorrectly passed `max_wait_time` to rdkafka (ms instead of seconds) causing too long wait.
|
75
|
+
- [Fix] Remove aggresive requerying of the Kafka cluster on topic creation/removal/altering.
|
61
76
|
- [Change] Move to trusted-publishers and remove signing since no longer needed.
|
62
77
|
|
63
78
|
## 2.4.18 (2025-04-09)
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
karafka (2.5.0.
|
4
|
+
karafka (2.5.0.rc2)
|
5
5
|
base64 (~> 0.2)
|
6
|
-
karafka-core (>= 2.5.
|
7
|
-
karafka-rdkafka (>= 0.19.
|
6
|
+
karafka-core (>= 2.5.2, < 2.6.0)
|
7
|
+
karafka-rdkafka (>= 0.19.5)
|
8
8
|
waterdrop (>= 2.8.3, < 3.0.0)
|
9
9
|
zeitwerk (~> 2.3)
|
10
10
|
|
@@ -27,9 +27,9 @@ GEM
|
|
27
27
|
securerandom (>= 0.3)
|
28
28
|
tzinfo (~> 2.0, >= 2.0.5)
|
29
29
|
uri (>= 0.13.1)
|
30
|
-
base64 (0.
|
31
|
-
benchmark (0.4.
|
32
|
-
bigdecimal (3.
|
30
|
+
base64 (0.3.0)
|
31
|
+
benchmark (0.4.1)
|
32
|
+
bigdecimal (3.2.2)
|
33
33
|
byebug (12.0.0)
|
34
34
|
concurrent-ruby (1.3.5)
|
35
35
|
connection_pool (2.5.3)
|
@@ -39,7 +39,7 @@ GEM
|
|
39
39
|
erubi (1.13.1)
|
40
40
|
et-orbi (1.2.11)
|
41
41
|
tzinfo
|
42
|
-
factory_bot (6.5.
|
42
|
+
factory_bot (6.5.4)
|
43
43
|
activesupport (>= 6.1.0)
|
44
44
|
ffi (1.17.2)
|
45
45
|
ffi (1.17.2-aarch64-linux-gnu)
|
@@ -59,19 +59,19 @@ GEM
|
|
59
59
|
activesupport (>= 6.1)
|
60
60
|
i18n (1.14.7)
|
61
61
|
concurrent-ruby (~> 1.0)
|
62
|
-
karafka-core (2.5.
|
62
|
+
karafka-core (2.5.2)
|
63
63
|
karafka-rdkafka (>= 0.19.2, < 0.21.0)
|
64
64
|
logger (>= 1.6.0)
|
65
|
-
karafka-rdkafka (0.19.
|
65
|
+
karafka-rdkafka (0.19.5)
|
66
66
|
ffi (~> 1.15)
|
67
67
|
mini_portile2 (~> 2.6)
|
68
68
|
rake (> 12)
|
69
|
-
karafka-testing (2.5.
|
69
|
+
karafka-testing (2.5.1)
|
70
70
|
karafka (>= 2.5.0.beta1, < 2.6.0)
|
71
71
|
waterdrop (>= 2.8.0)
|
72
|
-
karafka-web (0.11.0.
|
72
|
+
karafka-web (0.11.0.rc2)
|
73
73
|
erubi (~> 1.4)
|
74
|
-
karafka (>= 2.5.0.
|
74
|
+
karafka (>= 2.5.0.rc1, < 2.6.0)
|
75
75
|
karafka-core (>= 2.5.0, < 2.6.0)
|
76
76
|
roda (~> 3.68, >= 3.69)
|
77
77
|
tilt (~> 2.0)
|
@@ -81,22 +81,22 @@ GEM
|
|
81
81
|
ostruct (0.6.1)
|
82
82
|
raabro (1.4.0)
|
83
83
|
rack (3.1.15)
|
84
|
-
rake (13.
|
84
|
+
rake (13.3.0)
|
85
85
|
roda (3.92.0)
|
86
86
|
rack
|
87
|
-
rspec (3.13.
|
87
|
+
rspec (3.13.1)
|
88
88
|
rspec-core (~> 3.13.0)
|
89
89
|
rspec-expectations (~> 3.13.0)
|
90
90
|
rspec-mocks (~> 3.13.0)
|
91
|
-
rspec-core (3.13.
|
91
|
+
rspec-core (3.13.4)
|
92
92
|
rspec-support (~> 3.13.0)
|
93
|
-
rspec-expectations (3.13.
|
93
|
+
rspec-expectations (3.13.5)
|
94
94
|
diff-lcs (>= 1.2.0, < 2.0)
|
95
95
|
rspec-support (~> 3.13.0)
|
96
|
-
rspec-mocks (3.13.
|
96
|
+
rspec-mocks (3.13.5)
|
97
97
|
diff-lcs (>= 1.2.0, < 2.0)
|
98
98
|
rspec-support (~> 3.13.0)
|
99
|
-
rspec-support (3.13.
|
99
|
+
rspec-support (3.13.4)
|
100
100
|
securerandom (0.4.1)
|
101
101
|
simplecov (0.22.0)
|
102
102
|
docile (~> 1.1)
|
@@ -113,7 +113,7 @@ GEM
|
|
113
113
|
karafka-core (>= 2.4.9, < 3.0.0)
|
114
114
|
karafka-rdkafka (>= 0.19.2)
|
115
115
|
zeitwerk (~> 2.3)
|
116
|
-
zeitwerk (2.
|
116
|
+
zeitwerk (2.7.3)
|
117
117
|
|
118
118
|
PLATFORMS
|
119
119
|
aarch64-linux-gnu
|
@@ -135,7 +135,7 @@ DEPENDENCIES
|
|
135
135
|
fugit
|
136
136
|
karafka!
|
137
137
|
karafka-testing (>= 2.5.0)
|
138
|
-
karafka-web (>= 0.11.0.
|
138
|
+
karafka-web (>= 0.11.0.rc2)
|
139
139
|
ostruct
|
140
140
|
rspec
|
141
141
|
simplecov
|
data/bin/integrations
CHANGED
@@ -45,6 +45,7 @@ class Scenario
|
|
45
45
|
'shutdown/on_hanging_on_shutdown_job_and_a_shutdown_spec.rb' => [2].freeze,
|
46
46
|
'shutdown/on_hanging_listener_and_shutdown_spec.rb' => [2].freeze,
|
47
47
|
'swarm/forceful_shutdown_of_hanging_spec.rb' => [2].freeze,
|
48
|
+
'swarm/with_blocking_at_exit_spec.rb' => [2].freeze,
|
48
49
|
'instrumentation/post_errors_instrumentation_error_spec.rb' => [1].freeze,
|
49
50
|
'cli/declaratives/delete/existing_with_exit_code_spec.rb' => [2].freeze,
|
50
51
|
'cli/declaratives/create/new_with_exit_code_spec.rb' => [2].freeze,
|
data/config/locales/errors.yml
CHANGED
@@ -84,7 +84,8 @@ en:
|
|
84
84
|
admin.kafka_format: needs to be a hash
|
85
85
|
admin.group_id_format: 'needs to be a string with a Kafka accepted format'
|
86
86
|
admin.max_wait_time_format: 'needs to be an integer bigger than 0'
|
87
|
-
admin.
|
87
|
+
admin.retry_backoff_format: 'needs to be an integer bigger than 100'
|
88
|
+
admin.max_retries_duration_format: 'needs to be an integer bigger than 1000'
|
88
89
|
|
89
90
|
swarm.nodes_format: 'needs to be an integer bigger than 0'
|
90
91
|
swarm.node_format: needs to be false or node instance
|
data/docker-compose.yml
CHANGED
File without changes
|
data/karafka.gemspec
CHANGED
@@ -22,8 +22,8 @@ Gem::Specification.new do |spec|
|
|
22
22
|
DESC
|
23
23
|
|
24
24
|
spec.add_dependency 'base64', '~> 0.2'
|
25
|
-
spec.add_dependency 'karafka-core', '>= 2.5.
|
26
|
-
spec.add_dependency 'karafka-rdkafka', '>= 0.19.
|
25
|
+
spec.add_dependency 'karafka-core', '>= 2.5.2', '< 2.6.0'
|
26
|
+
spec.add_dependency 'karafka-rdkafka', '>= 0.19.5'
|
27
27
|
spec.add_dependency 'waterdrop', '>= 2.8.3', '< 3.0.0'
|
28
28
|
spec.add_dependency 'zeitwerk', '~> 2.3'
|
29
29
|
|
@@ -21,7 +21,10 @@ module Karafka
|
|
21
21
|
|
22
22
|
# Make sure, that karafka options that someone wants to use are valid before assigning
|
23
23
|
# them
|
24
|
-
App.config.internal.active_job.job_options_contract.validate!(
|
24
|
+
App.config.internal.active_job.job_options_contract.validate!(
|
25
|
+
new_options,
|
26
|
+
scope: %w[active_job]
|
27
|
+
)
|
25
28
|
|
26
29
|
# We need to modify this hash because otherwise we would modify parent hash.
|
27
30
|
self._karafka_options = _karafka_options.dup
|
data/lib/karafka/admin.rb
CHANGED
@@ -10,10 +10,13 @@ module Karafka
|
|
10
10
|
# Cluster on which operations are performed can be changed via `admin.kafka` config, however
|
11
11
|
# there is no multi-cluster runtime support.
|
12
12
|
module Admin
|
13
|
+
extend Core::Helpers::Time
|
14
|
+
|
13
15
|
extend Helpers::ConfigImporter.new(
|
14
16
|
max_wait_time: %i[admin max_wait_time],
|
15
17
|
poll_timeout: %i[admin poll_timeout],
|
16
|
-
|
18
|
+
max_retries_duration: %i[admin max_retries_duration],
|
19
|
+
retry_backoff: %i[admin retry_backoff],
|
17
20
|
group_id: %i[admin group_id],
|
18
21
|
app_kafka: %i[kafka],
|
19
22
|
admin_kafka: %i[admin kafka]
|
@@ -122,7 +125,7 @@ module Karafka
|
|
122
125
|
handler = admin.create_topic(name, partitions, replication_factor, topic_config)
|
123
126
|
|
124
127
|
with_re_wait(
|
125
|
-
-> { handler.wait(max_wait_timeout:
|
128
|
+
-> { handler.wait(max_wait_timeout: max_wait_time_seconds) },
|
126
129
|
-> { topics_names.include?(name) }
|
127
130
|
)
|
128
131
|
end
|
@@ -136,7 +139,7 @@ module Karafka
|
|
136
139
|
handler = admin.delete_topic(name)
|
137
140
|
|
138
141
|
with_re_wait(
|
139
|
-
-> { handler.wait(max_wait_timeout:
|
142
|
+
-> { handler.wait(max_wait_timeout: max_wait_time_seconds) },
|
140
143
|
-> { !topics_names.include?(name) }
|
141
144
|
)
|
142
145
|
end
|
@@ -151,7 +154,7 @@ module Karafka
|
|
151
154
|
handler = admin.create_partitions(name, partitions)
|
152
155
|
|
153
156
|
with_re_wait(
|
154
|
-
-> { handler.wait(max_wait_timeout:
|
157
|
+
-> { handler.wait(max_wait_timeout: max_wait_time_seconds) },
|
155
158
|
-> { topic_info(name).fetch(:partition_count) >= partitions }
|
156
159
|
)
|
157
160
|
end
|
@@ -362,7 +365,7 @@ module Karafka
|
|
362
365
|
def delete_consumer_group(consumer_group_id)
|
363
366
|
with_admin do |admin|
|
364
367
|
handler = admin.delete_group(consumer_group_id)
|
365
|
-
handler.wait(max_wait_timeout:
|
368
|
+
handler.wait(max_wait_timeout: max_wait_time_seconds)
|
366
369
|
end
|
367
370
|
end
|
368
371
|
|
@@ -564,6 +567,12 @@ module Karafka
|
|
564
567
|
|
565
568
|
private
|
566
569
|
|
570
|
+
# @return [Integer] number of seconds to wait. `rdkafka` requires this value
|
571
|
+
# (`max_wait_time`) to be provided in seconds while we define it in ms hence the conversion
|
572
|
+
def max_wait_time_seconds
|
573
|
+
max_wait_time / 1_000.0
|
574
|
+
end
|
575
|
+
|
567
576
|
# Adds a new callback for given rdkafka instance for oauth token refresh (if needed)
|
568
577
|
#
|
569
578
|
# @param id [String, Symbol] unique (for the lifetime of instance) id that we use for
|
@@ -602,20 +611,23 @@ module Karafka
|
|
602
611
|
# @param handler [Proc] the wait handler operation
|
603
612
|
# @param breaker [Proc] extra condition upon timeout that indicates things were finished ok
|
604
613
|
def with_re_wait(handler, breaker)
|
605
|
-
|
606
|
-
|
614
|
+
start_time = monotonic_now
|
615
|
+
# Convert milliseconds to seconds for sleep
|
616
|
+
sleep_time = retry_backoff / 1000.0
|
607
617
|
|
608
|
-
|
618
|
+
loop do
|
619
|
+
handler.call
|
609
620
|
|
610
|
-
|
611
|
-
# not visible and we need to wait
|
612
|
-
raise(Errors::ResultNotVisibleError) unless breaker.call
|
613
|
-
rescue Rdkafka::AbstractHandle::WaitTimeoutError, Errors::ResultNotVisibleError
|
614
|
-
return if breaker.call
|
621
|
+
sleep(sleep_time)
|
615
622
|
|
616
|
-
|
623
|
+
return if breaker.call
|
624
|
+
rescue Rdkafka::AbstractHandle::WaitTimeoutError
|
625
|
+
return if breaker.call
|
617
626
|
|
618
|
-
|
627
|
+
next if monotonic_now - start_time < max_retries_duration
|
628
|
+
|
629
|
+
raise(Errors::ResultNotVisibleError)
|
630
|
+
end
|
619
631
|
end
|
620
632
|
|
621
633
|
# @param type [Symbol] type of config we want
|
@@ -427,6 +427,15 @@ module Karafka
|
|
427
427
|
@wrapped_kafka.committed(tpl)
|
428
428
|
end
|
429
429
|
|
430
|
+
# Reads watermark offsets for given topic
|
431
|
+
#
|
432
|
+
# @param topic [String] topic name
|
433
|
+
# @param partition [Integer] partition number
|
434
|
+
# @return [Array<Integer, Integer>] watermark offsets (low, high)
|
435
|
+
def query_watermark_offsets(topic, partition)
|
436
|
+
@wrapped_kafka.query_watermark_offsets(topic, partition)
|
437
|
+
end
|
438
|
+
|
430
439
|
private
|
431
440
|
|
432
441
|
# When we cannot store an offset, it means we no longer own the partition
|
@@ -44,7 +44,7 @@ module Karafka
|
|
44
44
|
# clusters can handle our requests.
|
45
45
|
#
|
46
46
|
# @param topic [String] topic name
|
47
|
-
# @param partition [
|
47
|
+
# @param partition [Integer] partition number
|
48
48
|
# @return [Array<Integer, Integer>] watermark offsets
|
49
49
|
def query_watermark_offsets(topic, partition)
|
50
50
|
l_config = @config.query_watermark_offsets
|
@@ -5,12 +5,13 @@ module Karafka
|
|
5
5
|
# Base contract for all Karafka contracts
|
6
6
|
class Base < ::Karafka::Core::Contractable::Contract
|
7
7
|
# @param data [Hash] data for validation
|
8
|
+
# @param scope [Array<String>] nested scope if in use
|
8
9
|
# @return [Boolean] true if all good
|
9
10
|
# @raise [Errors::InvalidConfigurationError] invalid configuration error
|
10
11
|
# @note We use contracts only in the config validation context, so no need to add support
|
11
12
|
# for multiple error classes. It will be added when it will be needed.
|
12
|
-
def validate!(data)
|
13
|
-
super(data, Errors::InvalidConfigurationError)
|
13
|
+
def validate!(data, scope: [])
|
14
|
+
super(data, Errors::InvalidConfigurationError, scope: scope)
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
@@ -53,7 +53,8 @@ module Karafka
|
|
53
53
|
required(:kafka) { |val| val.is_a?(Hash) }
|
54
54
|
required(:group_id) { |val| val.is_a?(String) && Contracts::TOPIC_REGEXP.match?(val) }
|
55
55
|
required(:max_wait_time) { |val| val.is_a?(Integer) && val.positive? }
|
56
|
-
required(:
|
56
|
+
required(:retry_backoff) { |val| val.is_a?(Integer) && val >= 100 }
|
57
|
+
required(:max_retries_duration) { |val| val.is_a?(Integer) && val >= 1_000 }
|
57
58
|
end
|
58
59
|
|
59
60
|
# We validate internals just to be sure, that they are present and working
|
@@ -30,6 +30,14 @@ module Karafka
|
|
30
30
|
@block.call
|
31
31
|
end
|
32
32
|
|
33
|
+
# Runs the requested code bypassing any time frequencies
|
34
|
+
# Useful when we have certain actions that usually need to run periodically but in some
|
35
|
+
# cases need to run asap
|
36
|
+
def call!
|
37
|
+
@last_called_at = monotonic_now
|
38
|
+
@block.call
|
39
|
+
end
|
40
|
+
|
33
41
|
# Resets the runner, so next `#call` will run the underlying code
|
34
42
|
def reset
|
35
43
|
@last_called_at = monotonic_now - @interval
|
@@ -76,7 +76,7 @@ module Karafka
|
|
76
76
|
consumer = job.executor.topic.consumer
|
77
77
|
topic = job.executor.topic.name
|
78
78
|
partition = job.executor.partition
|
79
|
-
info "[#{job.id}] #{job_type} job for #{consumer} on #{topic}
|
79
|
+
info "[#{job.id}] #{job_type} job for #{consumer} on #{topic}-#{partition} started"
|
80
80
|
end
|
81
81
|
|
82
82
|
# Prints info about the fact that a given job has finished
|
@@ -91,7 +91,7 @@ module Karafka
|
|
91
91
|
partition = job.executor.partition
|
92
92
|
info <<~MSG.tr("\n", ' ').strip!
|
93
93
|
[#{job.id}] #{job_type} job for #{consumer}
|
94
|
-
on #{topic}
|
94
|
+
on #{topic}-#{partition} finished in #{time} ms
|
95
95
|
MSG
|
96
96
|
end
|
97
97
|
|
@@ -108,7 +108,7 @@ module Karafka
|
|
108
108
|
|
109
109
|
info <<~MSG.tr("\n", ' ').strip!
|
110
110
|
[#{client.id}]
|
111
|
-
Pausing on topic #{topic}
|
111
|
+
Pausing on topic #{topic}-#{partition}
|
112
112
|
on #{offset ? "offset #{offset}" : 'the consecutive offset'}
|
113
113
|
MSG
|
114
114
|
end
|
@@ -122,7 +122,7 @@ module Karafka
|
|
122
122
|
client = event[:caller]
|
123
123
|
|
124
124
|
info <<~MSG.tr("\n", ' ').strip!
|
125
|
-
[#{client.id}] Resuming on topic #{topic}
|
125
|
+
[#{client.id}] Resuming on topic #{topic}-#{partition}
|
126
126
|
MSG
|
127
127
|
end
|
128
128
|
|
@@ -138,7 +138,7 @@ module Karafka
|
|
138
138
|
|
139
139
|
info <<~MSG.tr("\n", ' ').strip!
|
140
140
|
[#{consumer.id}] Retrying of #{consumer.class} after #{timeout} ms
|
141
|
-
on topic #{topic}
|
141
|
+
on topic #{topic}-#{partition} from offset #{offset}
|
142
142
|
MSG
|
143
143
|
end
|
144
144
|
|
@@ -153,7 +153,7 @@ module Karafka
|
|
153
153
|
|
154
154
|
info <<~MSG.tr("\n", ' ').strip!
|
155
155
|
[#{consumer.id}] Seeking from #{consumer.class}
|
156
|
-
on topic #{topic}
|
156
|
+
on topic #{topic}-#{partition} to offset #{seek_offset}
|
157
157
|
MSG
|
158
158
|
end
|
159
159
|
|
@@ -233,7 +233,7 @@ module Karafka
|
|
233
233
|
info "#{group_prefix}: No partitions revoked"
|
234
234
|
else
|
235
235
|
revoked_partitions.each do |topic, partitions|
|
236
|
-
info "#{group_prefix}:
|
236
|
+
info "#{group_prefix}: #{topic}-[#{partitions.join(',')}] revoked"
|
237
237
|
end
|
238
238
|
end
|
239
239
|
end
|
@@ -251,7 +251,7 @@ module Karafka
|
|
251
251
|
info "#{group_prefix}: No partitions assigned"
|
252
252
|
else
|
253
253
|
assigned_partitions.each do |topic, partitions|
|
254
|
-
info "#{group_prefix}:
|
254
|
+
info "#{group_prefix}: #{topic}-[#{partitions.join(',')}] assigned"
|
255
255
|
end
|
256
256
|
end
|
257
257
|
end
|
@@ -269,7 +269,7 @@ module Karafka
|
|
269
269
|
|
270
270
|
info <<~MSG.tr("\n", ' ').strip!
|
271
271
|
[#{consumer.id}] Dispatched message #{offset}
|
272
|
-
from #{topic}
|
272
|
+
from #{topic}-#{partition}
|
273
273
|
to DLQ topic: #{dlq_topic}
|
274
274
|
MSG
|
275
275
|
end
|
@@ -288,7 +288,7 @@ module Karafka
|
|
288
288
|
info <<~MSG.tr("\n", ' ').strip!
|
289
289
|
[#{consumer.id}] Throttled and will resume
|
290
290
|
from message #{offset}
|
291
|
-
on #{topic}
|
291
|
+
on #{topic}-#{partition}
|
292
292
|
MSG
|
293
293
|
end
|
294
294
|
|
@@ -303,7 +303,7 @@ module Karafka
|
|
303
303
|
|
304
304
|
info <<~MSG.tr("\n", ' ').strip!
|
305
305
|
[#{consumer.id}] Post-filtering seeking to message #{offset}
|
306
|
-
on #{topic}
|
306
|
+
on #{topic}-#{partition}
|
307
307
|
MSG
|
308
308
|
end
|
309
309
|
|
@@ -8,11 +8,12 @@ module Karafka
|
|
8
8
|
# Namespace for instrumentation related with Kubernetes
|
9
9
|
module Kubernetes
|
10
10
|
# Base Kubernetes Listener providing basic HTTP server capabilities to respond with health
|
11
|
+
# statuses
|
11
12
|
class BaseListener
|
12
13
|
include ::Karafka::Core::Helpers::Time
|
13
14
|
|
14
15
|
# All good with Karafka
|
15
|
-
OK_CODE = '
|
16
|
+
OK_CODE = '200 OK'
|
16
17
|
|
17
18
|
# Some timeouts, fail
|
18
19
|
FAIL_CODE = '500 Internal Server Error'
|
@@ -38,11 +39,15 @@ module Karafka
|
|
38
39
|
|
39
40
|
# Responds to a HTTP request with the process liveness status
|
40
41
|
def respond
|
42
|
+
body = JSON.generate(status_body)
|
43
|
+
|
41
44
|
client = @server.accept
|
42
45
|
client.gets
|
43
46
|
client.print "HTTP/1.1 #{healthy? ? OK_CODE : FAIL_CODE}\r\n"
|
44
|
-
client.print "Content-Type:
|
47
|
+
client.print "Content-Type: application/json\r\n"
|
48
|
+
client.print "Content-Length: #{body.bytesize}\r\n"
|
45
49
|
client.print "\r\n"
|
50
|
+
client.print body
|
46
51
|
client.close
|
47
52
|
|
48
53
|
true
|
@@ -50,6 +55,16 @@ module Karafka
|
|
50
55
|
!@server.closed?
|
51
56
|
end
|
52
57
|
|
58
|
+
# @return [Hash] hash that will be the response body
|
59
|
+
def status_body
|
60
|
+
{
|
61
|
+
status: healthy? ? 'healthy' : 'unhealthy',
|
62
|
+
timestamp: Time.now.to_i,
|
63
|
+
port: @port,
|
64
|
+
process_id: ::Process.pid
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
53
68
|
# Starts background thread with micro-http monitoring
|
54
69
|
def start
|
55
70
|
@server = TCPServer.new(*[@hostname, @port].compact)
|