karafka 2.0.23 → 2.0.26
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 +24 -3
- data/.ruby-version +1 -1
- data/CHANGELOG.md +52 -1
- data/Gemfile.lock +14 -12
- data/README.md +6 -4
- data/bin/integrations +8 -0
- data/bin/verify_license_integrity +35 -0
- data/config/{errors.yml → locales/errors.yml} +2 -1
- data/config/locales/pro_errors.yml +18 -0
- data/docker-compose.yml +3 -0
- data/karafka.gemspec +3 -3
- data/lib/karafka/active_job/job_options_contract.rb +1 -1
- data/lib/karafka/admin.rb +16 -14
- data/lib/karafka/app.rb +16 -4
- data/lib/karafka/base_consumer.rb +37 -7
- data/lib/karafka/connection/client.rb +21 -0
- data/lib/karafka/connection/consumer_group_coordinator.rb +7 -1
- data/lib/karafka/connection/listener.rb +5 -4
- data/lib/karafka/connection/listeners_batch.rb +6 -0
- 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 +2 -1
- data/lib/karafka/contracts/topic.rb +13 -2
- data/lib/karafka/instrumentation/logger_listener.rb +50 -2
- data/lib/karafka/instrumentation/notifications.rb +17 -7
- data/lib/karafka/instrumentation/proctitle_listener.rb +7 -16
- data/lib/karafka/instrumentation/vendors/datadog/listener.rb +2 -2
- 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 +22 -1
- data/lib/karafka/pro/processing/strategies/aj_dlq_mom.rb +1 -1
- data/lib/karafka/pro/processing/strategies/aj_lrj_mom_vp.rb +6 -1
- data/lib/karafka/pro/processing/strategies/aj_mom_vp.rb +1 -1
- data/lib/karafka/pro/processing/strategies/default.rb +7 -1
- data/lib/karafka/pro/processing/strategies/dlq.rb +1 -1
- data/lib/karafka/pro/processing/strategies/dlq_lrj.rb +1 -1
- data/lib/karafka/pro/processing/strategies/dlq_lrj_mom.rb +1 -1
- data/lib/karafka/pro/processing/strategies/dlq_mom.rb +1 -1
- data/lib/karafka/pro/processing/strategies/lrj.rb +6 -1
- data/lib/karafka/pro/processing/strategies/lrj_mom.rb +6 -1
- 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/process.rb +3 -1
- data/lib/karafka/processing/executor.rb +1 -1
- data/lib/karafka/processing/jobs_queue.rb +2 -2
- data/lib/karafka/processing/strategies/aj_dlq_mom.rb +1 -1
- data/lib/karafka/processing/strategies/base.rb +5 -0
- data/lib/karafka/processing/strategies/default.rb +15 -1
- data/lib/karafka/processing/strategies/dlq.rb +1 -1
- data/lib/karafka/processing/strategies/dlq_mom.rb +1 -1
- data/lib/karafka/processing/strategies/mom.rb +1 -1
- data/lib/karafka/processing/worker.rb +3 -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/consumer_mapper.rb +0 -10
- 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/routing/router.rb +12 -2
- data/lib/karafka/routing/subscription_group.rb +18 -1
- data/lib/karafka/routing/topic.rb +11 -0
- data/lib/karafka/runner.rb +1 -0
- data/lib/karafka/server.rb +27 -18
- data/lib/karafka/setup/config.rb +15 -2
- data/lib/karafka/status.rb +33 -9
- data/lib/karafka/templates/karafka.rb.erb +1 -2
- data/lib/karafka/time_trackers/base.rb +1 -6
- data/lib/karafka/time_trackers/pause.rb +5 -3
- data/lib/karafka/time_trackers/poll.rb +2 -2
- data/lib/karafka/version.rb +1 -1
- data/lib/karafka.rb +2 -0
- data.tar.gz.sig +0 -0
- metadata +18 -8
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1e0356b40b0812dc321a825731c6fcd7413f9d1d30a23288597d2f832c6b5d3
|
4
|
+
data.tar.gz: f887c3bc93f945329fa4bba4bcc81a8f95a9d5153fae64aa5b0936935502909d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 32b9c06212b90bb49232931a06e9ae445b76c2c8780c0774923945458dd425233c37167825c5d1f39118cdebb8352f6a014a8e547947367fa712e46fe07c96d5
|
7
|
+
data.tar.gz: 2047da1a400328dd13465f9c94b033a9841675b6e7274fc9d94a1677866d0feb9611858a02296a20e6e7b8ea589c0b903ae35e572c6c6ad6c8a3040300692703
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.github/workflows/ci.yml
CHANGED
@@ -25,7 +25,7 @@ jobs:
|
|
25
25
|
- name: Set up Ruby
|
26
26
|
uses: ruby/setup-ruby@v1
|
27
27
|
with:
|
28
|
-
ruby-version: 3.
|
28
|
+
ruby-version: 3.2
|
29
29
|
bundler-cache: true
|
30
30
|
|
31
31
|
- name: Install Diffend plugin
|
@@ -34,6 +34,22 @@ jobs:
|
|
34
34
|
- name: Bundle Secure
|
35
35
|
run: bundle secure
|
36
36
|
|
37
|
+
karafka-checksum:
|
38
|
+
runs-on: ubuntu-latest
|
39
|
+
strategy:
|
40
|
+
fail-fast: false
|
41
|
+
steps:
|
42
|
+
- uses: actions/checkout@v3
|
43
|
+
with:
|
44
|
+
fetch-depth: 0
|
45
|
+
- name: Run Karafka license checksum verification
|
46
|
+
env:
|
47
|
+
KARAFKA_PRO_USERNAME: ${{ secrets.KARAFKA_PRO_USERNAME }}
|
48
|
+
KARAFKA_PRO_PASSWORD: ${{ secrets.KARAFKA_PRO_PASSWORD }}
|
49
|
+
KARAFKA_PRO_VERSION: ${{ secrets.KARAFKA_PRO_VERSION }}
|
50
|
+
KARAFKA_PRO_LICENSE_CHECKSUM: ${{ secrets.KARAFKA_PRO_LICENSE_CHECKSUM }}
|
51
|
+
run: bin/verify_license_integrity
|
52
|
+
|
37
53
|
coditsu:
|
38
54
|
runs-on: ubuntu-latest
|
39
55
|
strategy:
|
@@ -46,12 +62,14 @@ jobs:
|
|
46
62
|
run: \curl -sSL https://api.coditsu.io/run/ci | bash
|
47
63
|
|
48
64
|
specs:
|
65
|
+
timeout-minutes: 30
|
49
66
|
runs-on: ubuntu-latest
|
50
67
|
needs: diffend
|
51
68
|
strategy:
|
52
69
|
fail-fast: false
|
53
70
|
matrix:
|
54
71
|
ruby:
|
72
|
+
- '3.2'
|
55
73
|
# We run it against the oldest and the newest of a given major to make sure, that there
|
56
74
|
# are no syntax-sugars that we would use that were introduced down the road
|
57
75
|
- '3.1'
|
@@ -61,7 +79,7 @@ jobs:
|
|
61
79
|
- '2.7'
|
62
80
|
- '2.7.0'
|
63
81
|
include:
|
64
|
-
- ruby: '3.
|
82
|
+
- ruby: '3.2'
|
65
83
|
coverage: 'true'
|
66
84
|
steps:
|
67
85
|
- uses: actions/checkout@v3
|
@@ -84,17 +102,19 @@ jobs:
|
|
84
102
|
run: bin/rspecs
|
85
103
|
|
86
104
|
integrations:
|
105
|
+
timeout-minutes: 30
|
87
106
|
runs-on: ubuntu-latest
|
88
107
|
needs: diffend
|
89
108
|
strategy:
|
90
109
|
fail-fast: false
|
91
110
|
matrix:
|
92
111
|
ruby:
|
112
|
+
- '3.2'
|
93
113
|
- '3.1'
|
94
114
|
- '3.0'
|
95
115
|
- '2.7'
|
96
116
|
include:
|
97
|
-
- ruby: '3.
|
117
|
+
- ruby: '3.2'
|
98
118
|
coverage: 'true'
|
99
119
|
steps:
|
100
120
|
- uses: actions/checkout@v3
|
@@ -130,5 +150,6 @@ jobs:
|
|
130
150
|
KARAFKA_PRO_USERNAME: ${{ secrets.KARAFKA_PRO_USERNAME }}
|
131
151
|
KARAFKA_PRO_PASSWORD: ${{ secrets.KARAFKA_PRO_PASSWORD }}
|
132
152
|
KARAFKA_PRO_VERSION: ${{ secrets.KARAFKA_PRO_VERSION }}
|
153
|
+
KARAFKA_PRO_LICENSE_CHECKSUM: ${{ secrets.KARAFKA_PRO_LICENSE_CHECKSUM }}
|
133
154
|
GITHUB_COVERAGE: ${{matrix.coverage}}
|
134
155
|
run: bin/integrations
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.2.0
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,56 @@
|
|
1
1
|
# Karafka framework changelog
|
2
2
|
|
3
|
+
## 2.0.26 (2023-01-10)
|
4
|
+
- **[Feature]** Allow for disabling given topics by setting `active` to false. It will exclude them from consumption but will allow to have their definitions for using admin APIs, etc.
|
5
|
+
- [Improvement] Early terminate on `read_topic` when reaching the last offset available on the request time.
|
6
|
+
- [Improvement] Introduce a `quiet` state that indicates that Karafka is not only moving to quiet mode but actually that it reached it and no work will happen anymore in any of the consumer groups.
|
7
|
+
- [Improvement] Use Karafka defined routes topics when possible for `read_topic` admin API.
|
8
|
+
- [Improvement] Introduce `client.pause` and `client.resume` instrumentation hooks for tracking client topic partition pausing and resuming. This is alongside of `consumer.consuming.pause` that can be used to track both manual and automatic pausing with more granular consumer related details. The `client.*` should be used for low level tracking.
|
9
|
+
- [Improvement] Replace `LoggerListener` pause notification with one based on `client.pause` instead of `consumer.consuming.pause`.
|
10
|
+
- [Improvement] Expand `LoggerListener` with `client.resume` notification.
|
11
|
+
- [Improvement] Replace random anonymous subscription groups ids with stable once.
|
12
|
+
- [Improvement] Add `consumer.consume`, `consumer.revoke` and `consumer.shutting_down` notification events and move the revocation logic calling to strategies.
|
13
|
+
- [Change] Rename job queue statistics `processing` key to `busy`. No changes needed because naming in the DataDog listener stays the same.
|
14
|
+
- [Fix] Fix proctitle listener state changes reporting on new states.
|
15
|
+
- [Fix] Make sure all files descriptors are closed in the integration specs.
|
16
|
+
- [Fix] Fix a case where empty subscription groups could leak into the execution flow.
|
17
|
+
- [Fix] Fix `LoggerListener` reporting so it does not end with `.`.
|
18
|
+
- [Fix] Run previously defined (if any) signal traps created prior to Karafka signals traps.
|
19
|
+
|
20
|
+
## 2.0.25 (2023-01-10)
|
21
|
+
- Release yanked due to accidental release with local changes.
|
22
|
+
|
23
|
+
## 2.0.24 (2022-12-19)
|
24
|
+
- **[Feature]** Provide out of the box encryption support for Pro.
|
25
|
+
- [Improvement] Add instrumentation upon `#pause`.
|
26
|
+
- [Improvement] Add instrumentation upon retries.
|
27
|
+
- [Improvement] Assign `#id` to consumers similar to other entities for ease of debugging.
|
28
|
+
- [Improvement] Add retries and pausing to the default `LoggerListener`.
|
29
|
+
- [Improvement] Introduce a new final `terminated` state that will kick in prior to exit but after all the instrumentation and other things are done.
|
30
|
+
- [Improvement] Ensure that state transitions are thread-safe and ensure state transitions can occur in one direction.
|
31
|
+
- [Improvement] Optimize status methods proxying to `Karafka::App`.
|
32
|
+
- [Improvement] Allow for easier state usage by introducing explicit `#to_s` for reporting.
|
33
|
+
- [Improvement] Change auto-generated id from `SecureRandom#uuid` to `SecureRandom#hex(6)`
|
34
|
+
- [Improvement] Emit statistic every 5 seconds by default.
|
35
|
+
- [Improvement] Introduce general messages parser that can be swapped when needed.
|
36
|
+
- [Fix] Do not trigger code reloading when `consumer_persistence` is enabled.
|
37
|
+
- [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.
|
38
|
+
|
39
|
+
### Upgrade notes
|
40
|
+
|
41
|
+
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`:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
class KarafkaApp < Karafka::App
|
45
|
+
setup do |config|
|
46
|
+
# Other settings...
|
47
|
+
config.kafka = {
|
48
|
+
'statistics.interval.ms': 0
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
3
54
|
## 2.0.23 (2022-12-07)
|
4
55
|
- [Maintenance] Align with `waterdrop` and `karafka-core`
|
5
56
|
- [Improvement] Provide `Admin#read_topic` API to get topic data without subscribing.
|
@@ -425,7 +476,7 @@ There are several things in the plan already for 2.1 and beyond, including a web
|
|
425
476
|
- Small integration specs refactoring + specs for pausing scenarios
|
426
477
|
|
427
478
|
## 2.0.0-alpha6 (2022-04-17)
|
428
|
-
- Fix a bug, where upon missing boot file and Rails, railtie would fail with a generic exception (#818)
|
479
|
+
- Fix a bug, where upon missing boot file and Rails, railtie would fail with a generic exception (#818)
|
429
480
|
- Fix an issue with parallel pristine specs colliding with each other during `bundle install` (#820)
|
430
481
|
- Replace `consumer.consume` with `consumer.consumed` event to match the behaviour
|
431
482
|
- Make sure, that offset committing happens before the `consumer.consumed` event is propagated
|
data/Gemfile.lock
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
karafka (2.0.
|
5
|
-
karafka-core (>= 2.0.
|
4
|
+
karafka (2.0.26)
|
5
|
+
karafka-core (>= 2.0.8, < 3.0.0)
|
6
6
|
thor (>= 0.20)
|
7
|
-
waterdrop (>= 2.4.
|
7
|
+
waterdrop (>= 2.4.7, < 3.0.0)
|
8
8
|
zeitwerk (~> 2.3)
|
9
9
|
|
10
10
|
GEM
|
@@ -29,11 +29,11 @@ GEM
|
|
29
29
|
activesupport (>= 5.0)
|
30
30
|
i18n (1.12.0)
|
31
31
|
concurrent-ruby (~> 1.0)
|
32
|
-
karafka-core (2.0.
|
32
|
+
karafka-core (2.0.8)
|
33
33
|
concurrent-ruby (>= 1.1)
|
34
34
|
rdkafka (>= 0.12)
|
35
|
-
mini_portile2 (2.8.
|
36
|
-
minitest (5.
|
35
|
+
mini_portile2 (2.8.1)
|
36
|
+
minitest (5.17.0)
|
37
37
|
rake (13.0.6)
|
38
38
|
rdkafka (0.12.0)
|
39
39
|
ffi (~> 1.15)
|
@@ -45,14 +45,14 @@ GEM
|
|
45
45
|
rspec-mocks (~> 3.12.0)
|
46
46
|
rspec-core (3.12.0)
|
47
47
|
rspec-support (~> 3.12.0)
|
48
|
-
rspec-expectations (3.12.
|
48
|
+
rspec-expectations (3.12.1)
|
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)
|
55
|
-
simplecov (0.
|
55
|
+
simplecov (0.22.0)
|
56
56
|
docile (~> 1.1)
|
57
57
|
simplecov-html (~> 0.11)
|
58
58
|
simplecov_json_formatter (~> 0.1)
|
@@ -61,12 +61,14 @@ 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.
|
64
|
+
waterdrop (2.4.7)
|
65
|
+
karafka-core (>= 2.0.7, < 3.0.0)
|
66
66
|
zeitwerk (~> 2.3)
|
67
67
|
zeitwerk (2.6.6)
|
68
68
|
|
69
69
|
PLATFORMS
|
70
|
+
arm64-darwin-21
|
71
|
+
x86_64-darwin-21
|
70
72
|
x86_64-linux
|
71
73
|
|
72
74
|
DEPENDENCIES
|
@@ -78,4 +80,4 @@ DEPENDENCIES
|
|
78
80
|
simplecov
|
79
81
|
|
80
82
|
BUNDLED WITH
|
81
|
-
2.
|
83
|
+
2.4.2
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/karafka.svg)](http://badge.fury.io/rb/karafka)
|
5
5
|
[![Join the chat at https://slack.karafka.io](https://raw.githubusercontent.com/karafka/misc/master/slack.svg)](https://slack.karafka.io)
|
6
6
|
|
7
|
-
**Note**: Upgrade
|
7
|
+
**Note**: Upgrade instructions for migration from Karafka `1.4` to Karafka `2.0` can be found [here](https://karafka.io/docs/Upgrades-2.0/).
|
8
8
|
|
9
9
|
## About Karafka
|
10
10
|
|
@@ -40,6 +40,8 @@ Karafka **uses** threads to handle many messages simultaneously in the same proc
|
|
40
40
|
|
41
41
|
## Getting started
|
42
42
|
|
43
|
+
![karafka web ui](https://raw.githubusercontent.com/karafka/misc/master/printscreens/web-ui.png)
|
44
|
+
|
43
45
|
If you're entirely new to the subject, you can start with our "Kafka on Rails" articles series, which will get you up and running with the terminology and basic ideas behind using Kafka:
|
44
46
|
|
45
47
|
- [Kafka on Rails: Using Kafka with Ruby on Rails – Part 1 – Kafka basics and its advantages](https://mensfeld.pl/2017/11/kafka-on-rails-using-kafka-with-ruby-on-rails-part-1-kafka-basics-and-its-advantages/)
|
@@ -72,10 +74,10 @@ Karafka.producer.produce_sync(topic: 'example', payload: { 'ping' => 'pong' }.to
|
|
72
74
|
```bash
|
73
75
|
bundle exec karafka server
|
74
76
|
|
75
|
-
[
|
76
|
-
[
|
77
|
+
[86d47f0b92f7] Polled 1 message in 1000ms
|
78
|
+
[3732873c8a74] Consume job for ExampleConsumer on example started
|
77
79
|
{"ping"=>"pong"}
|
78
|
-
[
|
80
|
+
[3732873c8a74] Consume job for ExampleConsumer on example finished in 0ms
|
79
81
|
```
|
80
82
|
|
81
83
|
## Want to Upgrade? LGPL is not for you? Want to help?
|
data/bin/integrations
CHANGED
@@ -152,6 +152,13 @@ class Scenario
|
|
152
152
|
end
|
153
153
|
end
|
154
154
|
|
155
|
+
# Close all the files that are open, so they do not pile up
|
156
|
+
def close
|
157
|
+
@stdin.close
|
158
|
+
@stdout.close
|
159
|
+
@stderr.close
|
160
|
+
end
|
161
|
+
|
155
162
|
private
|
156
163
|
|
157
164
|
# Sets up a proper environment for a given spec to run and returns the run command
|
@@ -248,6 +255,7 @@ while finished_scenarios.size < scenarios.size
|
|
248
255
|
active_scenarios.select(&:finished?).each do |exited|
|
249
256
|
scenario = active_scenarios.delete(exited)
|
250
257
|
scenario.report
|
258
|
+
scenario.close
|
251
259
|
finished_scenarios << scenario
|
252
260
|
end
|
253
261
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# This script verifies integrity of the Pro license
|
4
|
+
# Run it before bundle install to ensure, that what you are fetching is what you expect
|
5
|
+
# Run it after bundle install to ensure that the local artefact was not compromised
|
6
|
+
|
7
|
+
#!/usr/bin/env bash
|
8
|
+
|
9
|
+
set -e
|
10
|
+
|
11
|
+
if [ "$MODE" != "after" ]; then
|
12
|
+
# Check the remote license prior to bundle installing
|
13
|
+
curl \
|
14
|
+
--fail \
|
15
|
+
-u $KARAFKA_PRO_USERNAME:$KARAFKA_PRO_PASSWORD \
|
16
|
+
https://gems.karafka.io/gems/karafka-license-$KARAFKA_PRO_VERSION.gem \
|
17
|
+
-o ./karafka-license.gem
|
18
|
+
else
|
19
|
+
# Check the local cached one after bundle install
|
20
|
+
cache_path=`ruby -e 'puts "#{Gem.dir}/cache/"'`
|
21
|
+
cp "$cache_path/karafka-license-$KARAFKA_PRO_VERSION.gem" ./karafka-license.gem
|
22
|
+
fi
|
23
|
+
|
24
|
+
detected=`sha256sum ./karafka-license.gem | awk '{ print $1 }'`
|
25
|
+
|
26
|
+
rm ./karafka-license.gem
|
27
|
+
|
28
|
+
echo -n "Karafka Pro license artifact checksum verification result: "
|
29
|
+
|
30
|
+
if [ "$detected" = "$KARAFKA_PRO_LICENSE_CHECKSUM" ]; then
|
31
|
+
echo "Success"
|
32
|
+
else
|
33
|
+
echo -e "\033[0;31mFailure!\033[0m"
|
34
|
+
exit 1
|
35
|
+
fi
|
@@ -44,6 +44,7 @@ en:
|
|
44
44
|
dead_letter_queue.max_retries_format: needs to be equal or bigger than 0
|
45
45
|
dead_letter_queue.topic_format: 'needs to be a string with a Kafka accepted format'
|
46
46
|
dead_letter_queue.active_format: needs to be either true or false
|
47
|
+
active_format: needs to be either true or false
|
47
48
|
|
48
49
|
consumer_group:
|
49
50
|
missing: needs to be present
|
@@ -63,7 +64,7 @@ en:
|
|
63
64
|
|
64
65
|
pro_topic:
|
65
66
|
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
|
67
|
+
virtual_partitions.max_partitions_format: needs to be equal or more than 1
|
67
68
|
manual_offset_management_not_with_virtual_partitions: cannot be used together with Virtual Partitions
|
68
69
|
long_running_job.active_format: needs to be either true or false
|
69
70
|
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
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.authors = ['Maciej Mensfeld']
|
13
13
|
spec.email = %w[contact@karafka.io]
|
14
14
|
spec.homepage = 'https://karafka.io'
|
15
|
-
spec.licenses = [
|
15
|
+
spec.licenses = %w[LGPL-3.0 Commercial]
|
16
16
|
spec.summary = 'Karafka is Ruby and Rails efficient Kafka processing framework.'
|
17
17
|
spec.description = <<-DESC
|
18
18
|
Karafka is Ruby and Rails efficient Kafka processing framework.
|
@@ -21,9 +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.
|
24
|
+
spec.add_dependency 'karafka-core', '>= 2.0.8', '< 3.0.0'
|
25
25
|
spec.add_dependency 'thor', '>= 0.20'
|
26
|
-
spec.add_dependency 'waterdrop', '>= 2.4.
|
26
|
+
spec.add_dependency 'waterdrop', '>= 2.4.7', '< 3.0.0'
|
27
27
|
spec.add_dependency 'zeitwerk', '~> 2.3'
|
28
28
|
|
29
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
@@ -30,29 +30,30 @@ module Karafka
|
|
30
30
|
# @param name [String, Symbol] topic name
|
31
31
|
# @param partition [Integer] partition
|
32
32
|
# @param count [Integer] how many messages we want to get at most
|
33
|
-
# @param
|
34
|
-
# will start from the latest offset
|
33
|
+
# @param start_offset [Integer] offset from which we should start. If -1 is provided
|
34
|
+
# (default) we will start from the latest offset
|
35
35
|
#
|
36
36
|
# @return [Array<Karafka::Messages::Message>] array with messages
|
37
|
-
def read_topic(name, partition, count,
|
37
|
+
def read_topic(name, partition, count, start_offset = -1)
|
38
38
|
messages = []
|
39
39
|
tpl = Rdkafka::Consumer::TopicPartitionList.new
|
40
40
|
|
41
41
|
with_consumer do |consumer|
|
42
|
-
|
43
|
-
|
44
|
-
offset = offsets.last - count
|
45
|
-
end
|
42
|
+
offsets = consumer.query_watermark_offsets(name, partition)
|
43
|
+
end_offset = offsets.last
|
46
44
|
|
47
|
-
|
45
|
+
start_offset = [0, offsets.last - count].max if start_offset.negative?
|
48
46
|
|
49
|
-
tpl.add_topic_and_partitions_with_offsets(name, partition =>
|
47
|
+
tpl.add_topic_and_partitions_with_offsets(name, partition => start_offset)
|
50
48
|
consumer.assign(tpl)
|
51
49
|
|
52
50
|
# We should poll as long as we don't have all the messages that we need or as long as
|
53
51
|
# we do not read all the messages from the topic
|
54
52
|
loop do
|
53
|
+
# If we've got as many messages as we've wanted stop
|
55
54
|
break if messages.size >= count
|
55
|
+
# If we've reached end of the topic messages, don't process more
|
56
|
+
break if !messages.empty? && end_offset <= messages.last.offset
|
56
57
|
|
57
58
|
message = consumer.poll(200)
|
58
59
|
messages << message if message
|
@@ -67,7 +68,10 @@ module Karafka
|
|
67
68
|
messages.map do |message|
|
68
69
|
Messages::Builders::Message.call(
|
69
70
|
message,
|
70
|
-
|
71
|
+
# Use topic from routes if we can match it or create a dummy one
|
72
|
+
# Dummy one is used in case we cannot match the topic with routes. This can happen
|
73
|
+
# when admin API is used to read topics that are not part of the routing
|
74
|
+
Routing::Router.find_by(name: name) || Topic.new(name, App.config.deserializer),
|
71
75
|
Time.now
|
72
76
|
)
|
73
77
|
end
|
@@ -116,8 +120,7 @@ module Karafka
|
|
116
120
|
# Creates admin instance and yields it. After usage it closes the admin instance
|
117
121
|
def with_admin
|
118
122
|
admin = config(:producer).admin
|
119
|
-
|
120
|
-
result
|
123
|
+
yield(admin)
|
121
124
|
ensure
|
122
125
|
admin&.close
|
123
126
|
end
|
@@ -125,8 +128,7 @@ module Karafka
|
|
125
128
|
# Creates consumer instance and yields it. After usage it closes the consumer instance
|
126
129
|
def with_consumer
|
127
130
|
consumer = config(:consumer).consumer
|
128
|
-
|
129
|
-
result
|
131
|
+
yield(consumer)
|
130
132
|
ensure
|
131
133
|
consumer&.close
|
132
134
|
end
|
data/lib/karafka/app.rb
CHANGED
@@ -29,16 +29,28 @@ module Karafka
|
|
29
29
|
.delete_if { |_, sgs| sgs.empty? }
|
30
30
|
.each { |_, sgs| sgs.each { |sg| sg.topics.delete_if { |top| !top.active? } } }
|
31
31
|
.each { |_, sgs| sgs.delete_if { |sg| sg.topics.empty? } }
|
32
|
+
.reject { |cg, _| cg.subscription_groups.empty? }
|
32
33
|
.to_h
|
33
34
|
end
|
34
35
|
|
35
36
|
# Just a nicer name for the consumer groups
|
36
37
|
alias routes consumer_groups
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
# Allow for easier status management via `Karafka::App` by aliasing status methods here
|
40
|
+
Status::STATES.each do |state, transition|
|
41
|
+
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
42
|
+
def #{state}
|
43
|
+
App.config.internal.status.#{state}
|
44
|
+
end
|
45
|
+
|
46
|
+
def #{state}?
|
47
|
+
App.config.internal.status.#{state}?
|
48
|
+
end
|
49
|
+
|
50
|
+
def #{transition}
|
51
|
+
App.config.internal.status.#{transition}
|
52
|
+
end
|
53
|
+
RUBY
|
42
54
|
end
|
43
55
|
|
44
56
|
# 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
|
@@ -92,10 +99,6 @@ module Karafka
|
|
92
99
|
# @private
|
93
100
|
def on_revoked
|
94
101
|
handle_revoked
|
95
|
-
|
96
|
-
Karafka.monitor.instrument('consumer.revoked', caller: self) do
|
97
|
-
revoked
|
98
|
-
end
|
99
102
|
rescue StandardError => e
|
100
103
|
Karafka.monitor.instrument(
|
101
104
|
'error.occurred',
|
@@ -109,9 +112,7 @@ module Karafka
|
|
109
112
|
#
|
110
113
|
# @private
|
111
114
|
def on_shutdown
|
112
|
-
|
113
|
-
shutdown
|
114
|
-
end
|
115
|
+
handle_shutdown
|
115
116
|
rescue StandardError => e
|
116
117
|
Karafka.monitor.instrument(
|
117
118
|
'error.occurred',
|
@@ -204,6 +205,17 @@ module Karafka
|
|
204
205
|
|
205
206
|
# Indicate, that user took a manual action of pausing
|
206
207
|
coordinator.manual_pause if manual_pause
|
208
|
+
|
209
|
+
Karafka.monitor.instrument(
|
210
|
+
'consumer.consuming.pause',
|
211
|
+
caller: self,
|
212
|
+
manual: manual_pause,
|
213
|
+
topic: messages.metadata.topic,
|
214
|
+
partition: messages.metadata.partition,
|
215
|
+
offset: offset,
|
216
|
+
timeout: coordinator.pause_tracker.current_timeout,
|
217
|
+
attempt: coordinator.pause_tracker.attempt
|
218
|
+
)
|
207
219
|
end
|
208
220
|
|
209
221
|
# Resumes processing of the current topic partition
|
@@ -232,5 +244,23 @@ module Karafka
|
|
232
244
|
def revoked?
|
233
245
|
coordinator.revoked?
|
234
246
|
end
|
247
|
+
|
248
|
+
# Pauses the processing from the last offset to retry on given message
|
249
|
+
# @private
|
250
|
+
def retry_after_pause
|
251
|
+
pause(coordinator.seek_offset, nil, false)
|
252
|
+
|
253
|
+
# Instrumentation needs to run **after** `#pause` invocation because we rely on the states
|
254
|
+
# set by `#pause`
|
255
|
+
Karafka.monitor.instrument(
|
256
|
+
'consumer.consuming.retry',
|
257
|
+
caller: self,
|
258
|
+
topic: messages.metadata.topic,
|
259
|
+
partition: messages.metadata.partition,
|
260
|
+
offset: coordinator.seek_offset,
|
261
|
+
timeout: coordinator.pause_tracker.current_timeout,
|
262
|
+
attempt: coordinator.pause_tracker.attempt
|
263
|
+
)
|
264
|
+
end
|
235
265
|
end
|
236
266
|
end
|
@@ -14,6 +14,9 @@ module Karafka
|
|
14
14
|
# @note Consumer name may change in case we regenerate it
|
15
15
|
attr_reader :name
|
16
16
|
|
17
|
+
# @return [String] id of the client
|
18
|
+
attr_reader :id
|
19
|
+
|
17
20
|
# How many times should we retry polling in case of a failure
|
18
21
|
MAX_POLL_RETRIES = 20
|
19
22
|
|
@@ -29,6 +32,7 @@ module Karafka
|
|
29
32
|
# with all the configuration details needed for us to create a client
|
30
33
|
# @return [Karafka::Connection::Rdk::Consumer]
|
31
34
|
def initialize(subscription_group)
|
35
|
+
@id = SecureRandom.hex(6)
|
32
36
|
# Name is set when we build consumer
|
33
37
|
@name = ''
|
34
38
|
@mutex = Mutex.new
|
@@ -165,6 +169,15 @@ module Karafka
|
|
165
169
|
|
166
170
|
return unless tpl
|
167
171
|
|
172
|
+
Karafka.monitor.instrument(
|
173
|
+
'client.pause',
|
174
|
+
caller: self,
|
175
|
+
subscription_group: @subscription_group,
|
176
|
+
topic: topic,
|
177
|
+
partition: partition,
|
178
|
+
offset: offset
|
179
|
+
)
|
180
|
+
|
168
181
|
@paused_tpls[topic][partition] = tpl
|
169
182
|
|
170
183
|
@kafka.pause(tpl)
|
@@ -195,6 +208,14 @@ module Karafka
|
|
195
208
|
# happen in the first place
|
196
209
|
return unless @paused_tpls[topic].delete(partition)
|
197
210
|
|
211
|
+
Karafka.monitor.instrument(
|
212
|
+
'client.resume',
|
213
|
+
caller: self,
|
214
|
+
subscription_group: @subscription_group,
|
215
|
+
topic: topic,
|
216
|
+
partition: partition
|
217
|
+
)
|
218
|
+
|
198
219
|
@kafka.resume(tpl)
|
199
220
|
ensure
|
200
221
|
@mutex.unlock
|
@@ -21,10 +21,16 @@ module Karafka
|
|
21
21
|
@finished = Set.new
|
22
22
|
end
|
23
23
|
|
24
|
+
# @return [Boolean] true if all the subscription groups from a given consumer group are
|
25
|
+
# finished
|
26
|
+
def finished?
|
27
|
+
@finished.size == @group_size
|
28
|
+
end
|
29
|
+
|
24
30
|
# @return [Boolean] can we start shutdown on a given listener
|
25
31
|
# @note If true, will also obtain a lock so no-one else will be closing the same time we do
|
26
32
|
def shutdown?
|
27
|
-
|
33
|
+
finished? && @shutdown_lock.try_lock
|
28
34
|
end
|
29
35
|
|
30
36
|
# Unlocks the shutdown lock
|