karafka 2.0.23 → 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/CHANGELOG.md +32 -1
- data/Gemfile.lock +8 -7
- 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 -2
- data/lib/karafka/active_job/job_options_contract.rb +1 -1
- data/lib/karafka/admin.rb +2 -4
- data/lib/karafka/app.rb +15 -4
- data/lib/karafka/base_consumer.rb +36 -0
- 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 +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 +1 -1
- data/lib/karafka/pro/processing/strategies/aj_mom_vp.rb +1 -1
- data/lib/karafka/pro/processing/strategies/default.rb +1 -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 +1 -1
- data/lib/karafka/pro/processing/strategies/lrj_mom.rb +1 -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/processing/executor.rb +1 -1
- data/lib/karafka/processing/strategies/aj_dlq_mom.rb +1 -1
- data/lib/karafka/processing/strategies/default.rb +1 -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 +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 +16 -7
- 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: 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/CHANGELOG.md
CHANGED
@@ -1,5 +1,36 @@
|
|
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
|
+
|
3
34
|
## 2.0.23 (2022-12-07)
|
4
35
|
- [Maintenance] Align with `waterdrop` and `karafka-core`
|
5
36
|
- [Improvement] Provide `Admin#read_topic` API to get topic data without subscribing.
|
@@ -425,7 +456,7 @@ There are several things in the plan already for 2.1 and beyond, including a web
|
|
425
456
|
- Small integration specs refactoring + specs for pausing scenarios
|
426
457
|
|
427
458
|
## 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)
|
459
|
+
- Fix a bug, where upon missing boot file and Rails, railtie would fail with a generic exception (#818)
|
429
460
|
- Fix an issue with parallel pristine specs colliding with each other during `bundle install` (#820)
|
430
461
|
- Replace `consumer.consume` with `consumer.consumed` event to match the behaviour
|
431
462
|
- 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.24)
|
5
|
+
karafka-core (>= 2.0.7, < 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,7 +29,7 @@ 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.7)
|
33
33
|
concurrent-ruby (>= 1.1)
|
34
34
|
rdkafka (>= 0.12)
|
35
35
|
mini_portile2 (2.8.0)
|
@@ -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,12 +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.
|
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
|
+
x86_64-darwin-21
|
70
71
|
x86_64-linux
|
71
72
|
|
72
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,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.7', '< 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
@@ -116,8 +116,7 @@ module Karafka
|
|
116
116
|
# Creates admin instance and yields it. After usage it closes the admin instance
|
117
117
|
def with_admin
|
118
118
|
admin = config(:producer).admin
|
119
|
-
|
120
|
-
result
|
119
|
+
yield(admin)
|
121
120
|
ensure
|
122
121
|
admin&.close
|
123
122
|
end
|
@@ -125,8 +124,7 @@ module Karafka
|
|
125
124
|
# Creates consumer instance and yields it. After usage it closes the consumer instance
|
126
125
|
def with_consumer
|
127
126
|
consumer = config(:consumer).consumer
|
128
|
-
|
129
|
-
result
|
127
|
+
yield(consumer)
|
130
128
|
ensure
|
131
129
|
consumer&.close
|
132
130
|
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
|
@@ -204,6 +211,17 @@ module Karafka
|
|
204
211
|
|
205
212
|
# Indicate, that user took a manual action of pausing
|
206
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
|
+
)
|
207
225
|
end
|
208
226
|
|
209
227
|
# Resumes processing of the current topic partition
|
@@ -232,5 +250,23 @@ module Karafka
|
|
232
250
|
def revoked?
|
233
251
|
coordinator.revoked?
|
234
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
|
235
271
|
end
|
236
272
|
end
|
@@ -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
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
5
|
+
#
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
7
|
+
# repository and their usage requires commercial license agreement.
|
8
|
+
#
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
10
|
+
#
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
12
|
+
# your code to Maciej Mensfeld.
|
13
|
+
|
14
|
+
module Karafka
|
15
|
+
module Pro
|
16
|
+
module Encryption
|
17
|
+
# Cipher for encrypting and decrypting data
|
18
|
+
class Cipher
|
19
|
+
def initialize
|
20
|
+
@private_pems = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
# Encrypts given string content with the public key
|
24
|
+
# @param content [String]
|
25
|
+
# @return [String]
|
26
|
+
def encrypt(content)
|
27
|
+
public_pem.public_encrypt(content)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Decrypts provided content using `version` key
|
31
|
+
# @param version [String] encryption version
|
32
|
+
# @param content [String] encrypted content
|
33
|
+
# @return [String] decrypted content
|
34
|
+
def decrypt(version, content)
|
35
|
+
private_pem(version).private_decrypt(content)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# @return [::OpenSSL::PKey::RSA] rsa public key
|
41
|
+
def public_pem
|
42
|
+
@public_pem ||= ::OpenSSL::PKey::RSA.new(::Karafka::App.config.encryption.public_key)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param version [String] version for which we want to get the rsa key
|
46
|
+
# @return [::OpenSSL::PKey::RSA] rsa private key
|
47
|
+
def private_pem(version)
|
48
|
+
return @private_pems[version] if @private_pems.key?(version)
|
49
|
+
|
50
|
+
key_string = ::Karafka::App.config.encryption.private_keys[version]
|
51
|
+
key_string || raise(Errors::PrivateKeyNotFound, version)
|
52
|
+
|
53
|
+
@private_pems[version] = ::OpenSSL::PKey::RSA.new(key_string)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
5
|
+
#
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
7
|
+
# repository and their usage requires commercial license agreement.
|
8
|
+
#
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
10
|
+
#
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
12
|
+
# your code to Maciej Mensfeld.
|
13
|
+
|
14
|
+
module Karafka
|
15
|
+
module Pro
|
16
|
+
module Encryption
|
17
|
+
# Encryption related contracts
|
18
|
+
module Contracts
|
19
|
+
# Makes sure, all the expected config is defined as it should be
|
20
|
+
class Config < ::Karafka::Contracts::Base
|
21
|
+
configure do |config|
|
22
|
+
config.error_messages = YAML.safe_load(
|
23
|
+
File.read(
|
24
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'pro_errors.yml')
|
25
|
+
)
|
26
|
+
).fetch('en').fetch('validations').fetch('config')
|
27
|
+
end
|
28
|
+
|
29
|
+
nested(:encryption) do
|
30
|
+
required(:active) { |val| [true, false].include?(val) }
|
31
|
+
required(:version) { |val| val.is_a?(String) && !val.empty? }
|
32
|
+
required(:public_key) { |val| val.is_a?(String) }
|
33
|
+
|
34
|
+
required(:private_keys) do |val|
|
35
|
+
val.is_a?(Hash) &&
|
36
|
+
val.keys.all? { |key| key.is_a?(String) } &&
|
37
|
+
val.values.all? { |key| key.is_a?(String) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Public key validation
|
42
|
+
virtual do |data, errors|
|
43
|
+
next unless errors.empty?
|
44
|
+
next unless data.fetch(:encryption).fetch(:active)
|
45
|
+
|
46
|
+
key = OpenSSL::PKey::RSA.new(data.fetch(:encryption).fetch(:public_key))
|
47
|
+
|
48
|
+
next unless key.private?
|
49
|
+
|
50
|
+
[[%i[encryption public_key], :needs_to_be_public]]
|
51
|
+
rescue OpenSSL::PKey::RSAError
|
52
|
+
[[%i[encryption public_key], :invalid]]
|
53
|
+
end
|
54
|
+
|
55
|
+
# Private keys validation
|
56
|
+
virtual do |data, errors|
|
57
|
+
next unless errors.empty?
|
58
|
+
next unless data.fetch(:encryption).fetch(:active)
|
59
|
+
|
60
|
+
private_keys = data.fetch(:encryption).fetch(:private_keys)
|
61
|
+
|
62
|
+
# Keys may be empty for production only envs
|
63
|
+
next if private_keys.empty?
|
64
|
+
|
65
|
+
keys = private_keys.each_value.map do |key|
|
66
|
+
OpenSSL::PKey::RSA.new(key)
|
67
|
+
end
|
68
|
+
|
69
|
+
next if keys.all?(&:private?)
|
70
|
+
|
71
|
+
[[%i[encryption private_keys], :need_to_be_private]]
|
72
|
+
rescue OpenSSL::PKey::RSAError
|
73
|
+
[[%i[encryption private_keys], :invalid]]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
5
|
+
#
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
7
|
+
# repository and their usage requires commercial license agreement.
|
8
|
+
#
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
10
|
+
#
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
12
|
+
# your code to Maciej Mensfeld.
|
13
|
+
|
14
|
+
module Karafka
|
15
|
+
module Pro
|
16
|
+
module Encryption
|
17
|
+
# Encryption related errors
|
18
|
+
module Errors
|
19
|
+
# Raised when we have encountered encryption key with version we do not have
|
20
|
+
PrivateKeyNotFound = Class.new(::Karafka::Errors::BaseError)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|