karafka 2.0.0.rc2 → 2.0.0.rc5
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/CHANGELOG.md +29 -2
- data/CONTRIBUTING.md +4 -8
- data/Gemfile.lock +9 -21
- data/LICENSE-COMM +1 -1
- data/README.md +46 -8
- data/bin/integrations +1 -1
- data/config/errors.yml +4 -0
- data/docker-compose.yml +3 -0
- data/karafka.gemspec +5 -5
- data/lib/karafka/active_job/consumer.rb +2 -0
- data/lib/karafka/connection/client.rb +9 -4
- data/lib/karafka/connection/listener.rb +21 -7
- data/lib/karafka/contracts/base.rb +1 -1
- data/lib/karafka/errors.rb +0 -3
- data/lib/karafka/instrumentation/callbacks/statistics.rb +1 -2
- data/lib/karafka/instrumentation/logger_listener.rb +27 -3
- data/lib/karafka/instrumentation/monitor.rb +14 -59
- data/lib/karafka/instrumentation/notifications.rb +52 -0
- data/lib/karafka/instrumentation/vendors/datadog/dashboard.json +1 -0
- data/lib/karafka/instrumentation/vendors/datadog/listener.rb +232 -0
- data/lib/karafka/patches/rdkafka/consumer.rb +1 -1
- data/lib/karafka/pro/active_job/dispatcher.rb +5 -2
- data/lib/karafka/pro/active_job/job_options_contract.rb +1 -0
- data/lib/karafka/pro/base_consumer.rb +2 -2
- data/lib/karafka/pro/contracts/base.rb +21 -0
- data/lib/karafka/pro/contracts/consumer_group.rb +34 -0
- data/lib/karafka/pro/contracts/consumer_group_topic.rb +33 -0
- data/lib/karafka/pro/loader.rb +21 -3
- data/lib/karafka/pro/processing/partitioner.rb +22 -3
- data/lib/karafka/pro/routing/builder_extensions.rb +30 -0
- data/lib/karafka/pro/routing/{extensions.rb → topic_extensions.rb} +2 -2
- data/lib/karafka/process.rb +1 -0
- data/lib/karafka/processing/jobs_queue.rb +11 -0
- data/lib/karafka/processing/worker.rb +4 -2
- data/lib/karafka/server.rb +3 -0
- data/lib/karafka/setup/config.rb +3 -3
- data/lib/karafka/version.rb +1 -1
- data/lib/karafka.rb +3 -2
- data.tar.gz.sig +0 -0
- metadata +27 -14
- 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: 52fde84aac9ffef63ecbc1d367e3bfdc7209f6c2904f2a7142f51b1bd0613002
|
4
|
+
data.tar.gz: 4b4e7838e19505469ec20a654a3d7bb9c2588f351f9ea64fdb05e224b476d562
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ebdda184eca4c7dcfe39821125ba7a8645336607300395de792a7c8808cde07f54f5382278946fab58af0e95f3a85ab05be9ed6e7b292fc7692922cb7890747
|
7
|
+
data.tar.gz: 416cb01ed1b6dac0681969ce72505d19855a041e7ceb29e369ed9fc80675755ad1f478a20ee2d1f2c0e925036ba6f08adda727f8ecd3f4f07f39f0be347ae4a1
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,32 @@
|
|
1
1
|
# Karafka framework changelog
|
2
2
|
|
3
|
+
## 2.0.0.rc5 (2022-08-01)
|
4
|
+
- Improve specs stability
|
5
|
+
- Improve forceful shutdown
|
6
|
+
- Add support for debug `TTIN` backtrace printing
|
7
|
+
- Fix a case where logger listener would not intercept `warn` level
|
8
|
+
- Require `rdkafka` >= `0.12`
|
9
|
+
- Replace statistics decorator with the one from `karafka-core`
|
10
|
+
|
11
|
+
## 2.0.0.rc4 (2022-07-28)
|
12
|
+
- Remove `dry-monitor`
|
13
|
+
- Use `karafka-core`
|
14
|
+
- Improve forceful shutdown resources finalization
|
15
|
+
- Cache consumer client name
|
16
|
+
|
17
|
+
## 2.0.0.rc3 (2022-07-26)
|
18
|
+
- Fix Pro partitioner hash function may not utilize all the threads (#907).
|
19
|
+
- Improve virtual partitions messages distribution.
|
20
|
+
- Add StatsD/DataDog optional monitoring listener + dashboard template.
|
21
|
+
- Validate that Pro consumer is always used for Pro subscription.
|
22
|
+
- Improve ActiveJob consumer shutdown behaviour.
|
23
|
+
- Change default `max_wait_time` to 1 second.
|
24
|
+
- Change default `max_messages` to 100 (#915).
|
25
|
+
- Move logger listener polling reporting level to debug when no messages (#916).
|
26
|
+
- Improve stability on aggressive rebalancing (multiple rebalances in a short period).
|
27
|
+
- Improve specs stability.
|
28
|
+
- Allow using `:key` and `:partition_key` for Enhanced Active Job partitioning.
|
29
|
+
|
3
30
|
## 2.0.0.rc2 (2022-07-19)
|
4
31
|
- Fix `example_consumer.rb.erb` `#shutdown` and `#revoked` signatures to correct once.
|
5
32
|
- Improve the install user experience (print status and created files).
|
@@ -52,8 +79,8 @@
|
|
52
79
|
- Fix a case where consecutive CTRL+C (non-stop) would case an exception during forced shutdown
|
53
80
|
- Add missing `consumer.prepared.error` into `LoggerListener`
|
54
81
|
- Delegate partition resuming from the consumers to listeners threads.
|
55
|
-
- Add support for Long
|
56
|
-
- Add support for Long
|
82
|
+
- Add support for Long-Running Jobs (LRJ) for ActiveJob [PRO]
|
83
|
+
- Add support for Long-Running Jobs for consumers [PRO]
|
57
84
|
- Allow `active_job_topic` to accept a block for extra topic related settings
|
58
85
|
- Remove no longer needed logger threads
|
59
86
|
- Auto-adapt number of processes for integration specs based on the number of CPUs
|
data/CONTRIBUTING.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# Contributing
|
2
2
|
|
3
3
|
## Introduction
|
4
4
|
|
@@ -8,11 +8,7 @@ We welcome any type of contribution, not only code. You can help with:
|
|
8
8
|
- **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
|
9
9
|
- **Marketing**: writing blog posts, howto's, printing stickers, ...
|
10
10
|
- **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
|
11
|
-
- **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
|
12
|
-
|
13
|
-
## Your First Contribution
|
14
|
-
|
15
|
-
Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
|
11
|
+
- **Code**: take a look at the [open issues](https://github.com/karafka/karafka/issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
|
16
12
|
|
17
13
|
## Submitting code
|
18
14
|
|
@@ -32,5 +28,5 @@ By sending a pull request to the pro components, you are agreeing to transfer th
|
|
32
28
|
|
33
29
|
## Questions
|
34
30
|
|
35
|
-
If you have any questions, create an [issue](
|
36
|
-
You can also reach us at
|
31
|
+
If you have any questions, create an [issue](https://github.com/karafka/karafka/issues) (protip: do a quick search first to see if someone else didn't ask the same question before!).
|
32
|
+
You can also reach us at contact@karafka.io.
|
data/Gemfile.lock
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
karafka (2.0.0.
|
5
|
-
|
6
|
-
rdkafka (>= 0.
|
4
|
+
karafka (2.0.0.rc5)
|
5
|
+
karafka-core (>= 2.0.2, < 3.0.0)
|
6
|
+
rdkafka (>= 0.12)
|
7
7
|
thor (>= 0.20)
|
8
|
-
waterdrop (>= 2.
|
8
|
+
waterdrop (>= 2.4.1, < 3.0.0)
|
9
9
|
zeitwerk (~> 2.3)
|
10
10
|
|
11
11
|
GEM
|
@@ -23,19 +23,6 @@ GEM
|
|
23
23
|
concurrent-ruby (1.1.10)
|
24
24
|
diff-lcs (1.5.0)
|
25
25
|
docile (1.4.0)
|
26
|
-
dry-configurable (0.15.0)
|
27
|
-
concurrent-ruby (~> 1.0)
|
28
|
-
dry-core (~> 0.6)
|
29
|
-
dry-core (0.8.0)
|
30
|
-
concurrent-ruby (~> 1.0)
|
31
|
-
dry-events (0.3.0)
|
32
|
-
concurrent-ruby (~> 1.0)
|
33
|
-
dry-core (~> 0.5, >= 0.5)
|
34
|
-
dry-monitor (0.6.1)
|
35
|
-
dry-configurable (~> 0.13, >= 0.13.0)
|
36
|
-
dry-core (~> 0.5, >= 0.5)
|
37
|
-
dry-events (~> 0.2)
|
38
|
-
zeitwerk (~> 2.5)
|
39
26
|
factory_bot (6.2.1)
|
40
27
|
activesupport (>= 5.0.0)
|
41
28
|
ffi (1.15.5)
|
@@ -43,6 +30,8 @@ GEM
|
|
43
30
|
activesupport (>= 5.0)
|
44
31
|
i18n (1.12.0)
|
45
32
|
concurrent-ruby (~> 1.0)
|
33
|
+
karafka-core (2.0.2)
|
34
|
+
concurrent-ruby (>= 1.1)
|
46
35
|
mini_portile2 (2.8.0)
|
47
36
|
minitest (5.16.2)
|
48
37
|
rake (13.0.6)
|
@@ -70,11 +59,10 @@ GEM
|
|
70
59
|
simplecov-html (0.12.3)
|
71
60
|
simplecov_json_formatter (0.1.4)
|
72
61
|
thor (1.2.1)
|
73
|
-
tzinfo (2.0.
|
62
|
+
tzinfo (2.0.5)
|
74
63
|
concurrent-ruby (~> 1.0)
|
75
|
-
waterdrop (2.
|
76
|
-
|
77
|
-
dry-monitor (~> 0.5)
|
64
|
+
waterdrop (2.4.1)
|
65
|
+
karafka-core (>= 2.0.2, < 3.0.0)
|
78
66
|
rdkafka (>= 0.10)
|
79
67
|
zeitwerk (~> 2.3)
|
80
68
|
zeitwerk (2.6.0)
|
data/LICENSE-COMM
CHANGED
@@ -30,7 +30,7 @@ The Open Source version of the Software (“LGPL Version”) is licensed under t
|
|
30
30
|
|
31
31
|
4. Ownership. Notwithstanding anything to the contrary contained herein, except for the limited license rights expressly provided herein, Maciej Mensfeld and its suppliers have and will retain all rights, title and interest (including, without limitation, all patent, copyright, trademark, trade secret and other intellectual property rights) in and to the Software and all copies, modifications and derivative works thereof (including any changes which incorporate any of your ideas, feedback or suggestions). You acknowledge that you are obtaining only a limited license right to the Software, and that irrespective of any use of the words “purchase”, “sale” or like terms hereunder no ownership rights are being conveyed to you under this Agreement or otherwise.
|
32
32
|
|
33
|
-
5. Fees and Payment. The Software license fees will be due and payable in full as set forth in the applicable invoice or at the time of purchase.
|
33
|
+
5. Fees and Payment. The Software license fees will be due and payable in full as set forth in the applicable invoice or at the time of purchase. There are no refunds beyond the remedy refund.
|
34
34
|
|
35
35
|
6. Support, Maintenance and Services. Subject to the terms and conditions of this Agreement, as set forth in your invoice, and as set forth on the Karafka Pro support page (https://github.com/karafka/karafka/wiki/Commercial-Support), support and maintenance services may be included with the purchase of your license subscription.
|
36
36
|
|
data/README.md
CHANGED
@@ -4,11 +4,18 @@
|
|
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**: All of the documentation here refers to Karafka `2.0
|
7
|
+
**Note**: All of the documentation here refers to Karafka `2.0.0.rc4` or higher. If you are looking for the documentation for Karafka `1.4`, please click [here](https://github.com/karafka/wiki/tree/1.4).
|
8
8
|
|
9
9
|
## About Karafka
|
10
10
|
|
11
|
-
Karafka is a multi-threaded
|
11
|
+
Karafka is a Ruby and Rails multi-threaded efficient Kafka processing framework that:
|
12
|
+
|
13
|
+
- Supports parallel processing in [multiple threads](https://github.com/karafka/karafka/wiki/Concurrency-and-multithreading) (also for a [single topic partition](https://github.com/karafka/karafka/wiki/Pro-Virtual-Partitions) work)
|
14
|
+
- Has [ActiveJob backend](https://github.com/karafka/karafka/wiki/Active-Job) support (including ordered jobs)
|
15
|
+
- [Automatically integrates](https://github.com/karafka/karafka/wiki/Integrating-with-Ruby-on-Rails-and-other-frameworks#integrating-with-ruby-on-rails=) with Ruby on Rails
|
16
|
+
- Supports in-development [code reloading](https://github.com/karafka/karafka/wiki/Auto-reload-of-code-changes-in-development)
|
17
|
+
- Is powered by [librdkafka](https://github.com/edenhill/librdkafka) (the Apache Kafka C/C++ client library)
|
18
|
+
- Has an out-of the box [StatsD/DataDog monitoring](https://github.com/karafka/karafka/wiki/Monitoring-and-logging) with a dashboard template.
|
12
19
|
|
13
20
|
```ruby
|
14
21
|
# Define what topics you want to consume with which consumers in karafka.rb
|
@@ -28,22 +35,51 @@ class EventsConsumer < ApplicationConsumer
|
|
28
35
|
end
|
29
36
|
```
|
30
37
|
|
31
|
-
Karafka **uses** threads to handle many messages
|
38
|
+
Karafka **uses** threads to handle many messages simultaneously in the same process. It does not require Rails but will integrate tightly with any Ruby on Rails applications to make event processing dead simple.
|
32
39
|
|
33
40
|
## Getting started
|
34
41
|
|
35
|
-
If you're
|
42
|
+
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:
|
36
43
|
|
37
44
|
- [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/)
|
38
|
-
- [Kafka on Rails: Using Kafka with Ruby on Rails – Part 2 – Getting started with
|
45
|
+
- [Kafka on Rails: Using Kafka with Ruby on Rails – Part 2 – Getting started with Rails and Kafka](https://mensfeld.pl/2018/01/kafka-on-rails-using-kafka-with-ruby-on-rails-part-2-getting-started-with-ruby-and-kafka/)
|
39
46
|
|
40
47
|
If you want to get started with Kafka and Karafka as fast as possible, then the best idea is to visit our [Getting started](https://github.com/karafka/karafka/wiki/Getting-started) guides and the [example apps repository](https://github.com/karafka/example-apps).
|
41
48
|
|
42
49
|
We also maintain many [integration specs](https://github.com/karafka/karafka/tree/master/spec/integrations) illustrating various use-cases and features of the framework.
|
43
50
|
|
51
|
+
### TL;DR (1 minute from setup to publishing and consuming messages)
|
52
|
+
|
53
|
+
**Prerequisites**: Kafka running. You can start it by following instructions from [here](https://github.com/karafka/karafka/wiki/Setting-up-Kafka).
|
54
|
+
|
55
|
+
1. Add and install Karafka:
|
56
|
+
|
57
|
+
```bash
|
58
|
+
bundle add karafka -v 2.0.0.rc4
|
59
|
+
|
60
|
+
bundle exec karafka install
|
61
|
+
```
|
62
|
+
|
63
|
+
2. Dispatch a message to the example topic using the Rails or Ruby console:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
Karafka.producer.produce_sync(topic: 'example', payload: { 'ping' => 'pong' }.to_json)
|
67
|
+
```
|
68
|
+
|
69
|
+
3. Run Karafka server and see the consumption magic happen:
|
70
|
+
|
71
|
+
```bash
|
72
|
+
bundle exec karafka server
|
73
|
+
|
74
|
+
[7616dc24-505a-417f-b87b-6bf8fc2d98c5] Polled 1 message in 1000ms
|
75
|
+
[dcf3a8d8-0bd9-433a-8f63-b70a0cdb0732] Consume job for ExampleConsumer on example started
|
76
|
+
{"ping"=>"pong"}
|
77
|
+
[dcf3a8d8-0bd9-433a-8f63-b70a0cdb0732] Consume job for ExampleConsumer on example finished in 0ms
|
78
|
+
```
|
79
|
+
|
44
80
|
## Want to Upgrade? LGPL is not for you? Want to help?
|
45
81
|
|
46
|
-
I also sell Karafka Pro
|
82
|
+
I also sell Karafka Pro subscriptions. It includes a commercial-friendly license, priority support, architecture consultations, and high throughput data processing-related features (virtual partitions, long-running jobs, and more).
|
47
83
|
|
48
84
|
**20%** of the income will be distributed back to other OSS projects that Karafka uses under the hood.
|
49
85
|
|
@@ -51,6 +87,8 @@ Help me provide high-quality open-source software. Please see the Karafka [homep
|
|
51
87
|
|
52
88
|
## Support
|
53
89
|
|
54
|
-
Karafka has [Wiki pages](https://github.com/karafka/karafka/wiki) for almost everything and a pretty decent [FAQ](https://github.com/karafka/karafka/wiki/FAQ). It covers the
|
90
|
+
Karafka has [Wiki pages](https://github.com/karafka/karafka/wiki) for almost everything and a pretty decent [FAQ](https://github.com/karafka/karafka/wiki/FAQ). It covers the installation, setup, and deployment, along with other useful details on how to run Karafka.
|
91
|
+
|
92
|
+
If you have questions about using Karafka, feel free to join our [Slack](https://slack.karafka.io) channel.
|
55
93
|
|
56
|
-
|
94
|
+
Karafka has priority support for technical and architectural questions that is part of the Karafka Pro subscription.
|
data/bin/integrations
CHANGED
@@ -37,7 +37,7 @@ class Scenario
|
|
37
37
|
'consumption/worker_critical_error_behaviour.rb' => [0, 2].freeze,
|
38
38
|
'shutdown/on_hanging_jobs_and_a_shutdown.rb' => [2].freeze,
|
39
39
|
'shutdown/on_hanging_on_shutdown_job_and_a_shutdown.rb' => [2].freeze,
|
40
|
-
'shutdown/
|
40
|
+
'shutdown/on_hanging_listener_and_shutdown.rb' => [2].freeze
|
41
41
|
}.freeze
|
42
42
|
|
43
43
|
private_constant :MAX_RUN_TIME, :EXIT_CODES
|
data/config/errors.yml
CHANGED
@@ -46,7 +46,11 @@ en:
|
|
46
46
|
missing: needs to be present
|
47
47
|
dispatch_method_format: needs to be either :produce_async or :produce_sync
|
48
48
|
partitioner_format: 'needs to respond to #call'
|
49
|
+
partition_key_type_format: 'needs to be either :key or :partition_key'
|
49
50
|
|
50
51
|
test:
|
51
52
|
missing: needs to be present
|
52
53
|
id_format: needs to be a String
|
54
|
+
|
55
|
+
pro_consumer_group_topic:
|
56
|
+
consumer_format: needs to inherit from Karafka::Pro::BaseConsumer and not Karafka::Consumer
|
data/docker-compose.yml
CHANGED
@@ -36,10 +36,13 @@ services:
|
|
36
36
|
integrations_17_02:2:1,\
|
37
37
|
integrations_18_02:2:1,\
|
38
38
|
integrations_19_02:2:1,\
|
39
|
+
integrations_20_02:2:1,\
|
40
|
+
integrations_21_02:2:1,\
|
39
41
|
integrations_00_03:3:1,\
|
40
42
|
integrations_01_03:3:1,\
|
41
43
|
integrations_02_03:3:1,\
|
42
44
|
integrations_03_03:3:1,\
|
45
|
+
integrations_04_03:3:1,\
|
43
46
|
integrations_00_10:10:1,\
|
44
47
|
integrations_01_10:10:1,\
|
45
48
|
benchmarks_00_01:1:1,\
|
data/karafka.gemspec
CHANGED
@@ -12,17 +12,17 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.authors = ['Maciej Mensfeld']
|
13
13
|
spec.email = %w[maciej@mensfeld.pl]
|
14
14
|
spec.homepage = 'https://karafka.io'
|
15
|
-
spec.summary = '
|
15
|
+
spec.summary = 'Efficient Kafka processing framework for Ruby and Rails'
|
16
16
|
spec.description = 'Framework used to simplify Apache Kafka based Ruby applications development'
|
17
17
|
spec.licenses = ['LGPL-3.0', 'Commercial']
|
18
18
|
|
19
|
-
spec.add_dependency '
|
20
|
-
spec.add_dependency 'rdkafka', '>= 0.
|
19
|
+
spec.add_dependency 'karafka-core', '>= 2.0.2', '< 3.0.0'
|
20
|
+
spec.add_dependency 'rdkafka', '>= 0.12'
|
21
21
|
spec.add_dependency 'thor', '>= 0.20'
|
22
|
-
spec.add_dependency 'waterdrop', '>= 2.
|
22
|
+
spec.add_dependency 'waterdrop', '>= 2.4.1', '< 3.0.0'
|
23
23
|
spec.add_dependency 'zeitwerk', '~> 2.3'
|
24
24
|
|
25
|
-
spec.required_ruby_version = '>= 2.
|
25
|
+
spec.required_ruby_version = '>= 2.7.0'
|
26
26
|
|
27
27
|
if $PROGRAM_NAME.end_with?('gem')
|
28
28
|
spec.signing_key = File.expand_path('~/.ssh/gem-private_key.pem')
|
@@ -9,6 +9,8 @@ module Karafka
|
|
9
9
|
# @note ActiveJob does not support batches, so we just run one message after another
|
10
10
|
def consume
|
11
11
|
messages.each do |message|
|
12
|
+
break if Karafka::App.stopping?
|
13
|
+
|
12
14
|
::ActiveJob::Base.execute(
|
13
15
|
# We technically speaking could set this as deserializer and reference it from the
|
14
16
|
# message instead of using the `#raw_payload`. This is not done on purpose to simplify
|
@@ -69,9 +69,6 @@ module Karafka
|
|
69
69
|
# Put a message to the buffer if there is one
|
70
70
|
@buffer << message if message
|
71
71
|
|
72
|
-
# Track time spent on all of the processing and polling
|
73
|
-
time_poll.checkpoint
|
74
|
-
|
75
72
|
# Upon polling rebalance manager might have been updated.
|
76
73
|
# If partition revocation happens, we need to remove messages from revoked partitions
|
77
74
|
# as well as ensure we do not have duplicated due to the offset reset for partitions
|
@@ -82,6 +79,9 @@ module Karafka
|
|
82
79
|
break
|
83
80
|
end
|
84
81
|
|
82
|
+
# Track time spent on all of the processing and polling
|
83
|
+
time_poll.checkpoint
|
84
|
+
|
85
85
|
# Finally once we've (potentially) removed revoked, etc, if no messages were returned
|
86
86
|
# we can break.
|
87
87
|
# Worth keeping in mind, that the rebalance manager might have been updated despite no
|
@@ -268,13 +268,18 @@ module Karafka
|
|
268
268
|
true
|
269
269
|
rescue Rdkafka::RdkafkaError => e
|
270
270
|
return false if e.code == :assignment_lost
|
271
|
-
return
|
271
|
+
return true if e.code == :no_offset
|
272
272
|
|
273
273
|
raise e
|
274
274
|
end
|
275
275
|
|
276
276
|
# Commits the stored offsets in a sync way and closes the consumer.
|
277
277
|
def close
|
278
|
+
# Once client is closed, we should not close it again
|
279
|
+
# This could only happen in case of a race-condition when forceful shutdown happens
|
280
|
+
# and triggers this from a different thread
|
281
|
+
return if @closed
|
282
|
+
|
278
283
|
@mutex.synchronize do
|
279
284
|
internal_commit_offsets(async: false)
|
280
285
|
|
@@ -34,6 +34,8 @@ module Karafka
|
|
34
34
|
# We can do this that way because we always first schedule jobs using messages before we
|
35
35
|
# fetch another batch.
|
36
36
|
@messages_buffer = MessagesBuffer.new(subscription_group)
|
37
|
+
@mutex = Mutex.new
|
38
|
+
@stopped = false
|
37
39
|
end
|
38
40
|
|
39
41
|
# Runs the main listener fetch loop.
|
@@ -51,6 +53,25 @@ module Karafka
|
|
51
53
|
fetch_loop
|
52
54
|
end
|
53
55
|
|
56
|
+
# Stops the jobs queue, triggers shutdown on all the executors (sync), commits offsets and
|
57
|
+
# stops kafka client.
|
58
|
+
#
|
59
|
+
# @note This method is not private despite being part of the fetch loop because in case of
|
60
|
+
# a forceful shutdown, it may be invoked from a separate thread
|
61
|
+
#
|
62
|
+
# @note We wrap it with a mutex exactly because of the above case of forceful shutdown
|
63
|
+
def shutdown
|
64
|
+
return if @stopped
|
65
|
+
|
66
|
+
@mutex.synchronize do
|
67
|
+
@stopped = true
|
68
|
+
@executors.clear
|
69
|
+
@coordinators.reset
|
70
|
+
@client.commit_offsets!
|
71
|
+
@client.stop
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
54
75
|
private
|
55
76
|
|
56
77
|
# Fetches the data and adds it to the jobs queue.
|
@@ -239,13 +260,6 @@ module Karafka
|
|
239
260
|
@client.batch_poll until @jobs_queue.empty?(@subscription_group.id)
|
240
261
|
end
|
241
262
|
|
242
|
-
# Stops the jobs queue, triggers shutdown on all the executors (sync), commits offsets and
|
243
|
-
# stops kafka client.
|
244
|
-
def shutdown
|
245
|
-
@client.commit_offsets!
|
246
|
-
@client.stop
|
247
|
-
end
|
248
|
-
|
249
263
|
# We can stop client without a problem, as it will reinitialize itself when running the
|
250
264
|
# `#fetch_loop` again. We just need to remember to also reset the runner as it is a long
|
251
265
|
# running one, so with a new connection to Kafka, we need to initialize the state of the
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Karafka
|
4
4
|
module Contracts
|
5
5
|
# Base contract for all Karafka contracts
|
6
|
-
class Base < ::
|
6
|
+
class Base < ::Karafka::Core::Contractable::Contract
|
7
7
|
# @param data [Hash] data for validation
|
8
8
|
# @return [Boolean] true if all good
|
9
9
|
# @raise [Errors::InvalidConfigurationError] invalid configuration error
|
data/lib/karafka/errors.rb
CHANGED
@@ -24,9 +24,6 @@ module Karafka
|
|
24
24
|
# Raised when we try to use Karafka CLI commands (except install) without a boot file
|
25
25
|
MissingBootFileError = Class.new(BaseError)
|
26
26
|
|
27
|
-
# Raised when want to hook up to an event that is not registered and supported
|
28
|
-
UnregisteredMonitorEventError = Class.new(BaseError)
|
29
|
-
|
30
27
|
# Raised when we've waited enough for shutting down a non-responsive process
|
31
28
|
ForcefulShutdownError = Class.new(BaseError)
|
32
29
|
|
@@ -16,8 +16,7 @@ module Karafka
|
|
16
16
|
@consumer_group_id = consumer_group_id
|
17
17
|
@client_name = client_name
|
18
18
|
@monitor = monitor
|
19
|
-
|
20
|
-
@statistics_decorator = ::WaterDrop::Instrumentation::Callbacks::StatisticsDecorator.new
|
19
|
+
@statistics_decorator = ::Karafka::Core::Monitoring::StatisticsDecorator.new
|
21
20
|
end
|
22
21
|
|
23
22
|
# Emits decorated statistics to the monitor
|
@@ -9,6 +9,7 @@ module Karafka
|
|
9
9
|
USED_LOG_LEVELS = %i[
|
10
10
|
debug
|
11
11
|
info
|
12
|
+
warn
|
12
13
|
error
|
13
14
|
fatal
|
14
15
|
].freeze
|
@@ -18,7 +19,7 @@ module Karafka
|
|
18
19
|
# @param event [Dry::Events::Event] event details including payload
|
19
20
|
def on_connection_listener_fetch_loop(event)
|
20
21
|
listener = event[:caller]
|
21
|
-
|
22
|
+
debug "[#{listener.id}] Polling messages..."
|
22
23
|
end
|
23
24
|
|
24
25
|
# Logs about messages that we've received from Kafka
|
@@ -28,7 +29,13 @@ module Karafka
|
|
28
29
|
listener = event[:caller]
|
29
30
|
time = event[:time]
|
30
31
|
messages_count = event[:messages_buffer].size
|
31
|
-
|
32
|
+
|
33
|
+
message = "[#{listener.id}] Polled #{messages_count} messages in #{time}ms"
|
34
|
+
|
35
|
+
# We don't want the "polled 0" in dev as it would spam the log
|
36
|
+
# Instead we publish only info when there was anything we could poll and fail over to the
|
37
|
+
# zero notifications when in debug mode
|
38
|
+
messages_count.zero? ? debug(message) : info(message)
|
32
39
|
end
|
33
40
|
|
34
41
|
# Prints info about the fact that a given job has started
|
@@ -54,11 +61,28 @@ module Karafka
|
|
54
61
|
info "[#{job.id}] #{job_type} job for #{consumer} on #{topic} finished in #{time}ms"
|
55
62
|
end
|
56
63
|
|
57
|
-
# Logs info about system signals that Karafka received
|
64
|
+
# Logs info about system signals that Karafka received and prints backtrace for threads in
|
65
|
+
# case of ttin
|
58
66
|
#
|
59
67
|
# @param event [Dry::Events::Event] event details including payload
|
60
68
|
def on_process_notice_signal(event)
|
61
69
|
info "Received #{event[:signal]} system signal"
|
70
|
+
|
71
|
+
# We print backtrace only for ttin
|
72
|
+
return unless event[:signal] == :SIGTTIN
|
73
|
+
|
74
|
+
# Inspired by Sidekiq
|
75
|
+
Thread.list.each do |thread|
|
76
|
+
tid = (thread.object_id ^ ::Process.pid).to_s(36)
|
77
|
+
|
78
|
+
warn "Thread TID-#{tid} #{thread['label']}"
|
79
|
+
|
80
|
+
if thread.backtrace
|
81
|
+
warn thread.backtrace.join("\n")
|
82
|
+
else
|
83
|
+
warn '<no backtrace available>'
|
84
|
+
end
|
85
|
+
end
|
62
86
|
end
|
63
87
|
|
64
88
|
# Logs info that we're initializing Karafka app.
|
@@ -1,66 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Karafka
|
4
|
-
# Namespace for all the things related with Karafka instrumentation process
|
5
4
|
module Instrumentation
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
app.initialized
|
21
|
-
app.running
|
22
|
-
app.stopping
|
23
|
-
app.stopped
|
24
|
-
|
25
|
-
consumer.consumed
|
26
|
-
consumer.revoked
|
27
|
-
consumer.shutdown
|
28
|
-
|
29
|
-
process.notice_signal
|
30
|
-
|
31
|
-
connection.listener.before_fetch_loop
|
32
|
-
connection.listener.fetch_loop
|
33
|
-
connection.listener.fetch_loop.received
|
34
|
-
|
35
|
-
worker.process
|
36
|
-
worker.processed
|
37
|
-
|
38
|
-
statistics.emitted
|
39
|
-
|
40
|
-
error.occurred
|
41
|
-
].freeze
|
42
|
-
|
43
|
-
private_constant :BASE_EVENTS
|
44
|
-
|
45
|
-
# @return [Karafka::Instrumentation::Monitor] monitor instance for system instrumentation
|
46
|
-
def initialize
|
47
|
-
super(:karafka)
|
48
|
-
BASE_EVENTS.each(&method(:register_event))
|
49
|
-
end
|
50
|
-
|
51
|
-
# Allows us to subscribe to events with a code that will be yielded upon events
|
52
|
-
# @param event_name_or_listener [String, Object] name of the event we want to subscribe to
|
53
|
-
# or a listener if we decide to go with object listener
|
54
|
-
def subscribe(event_name_or_listener)
|
55
|
-
return super unless event_name_or_listener.is_a?(String)
|
56
|
-
return super if available_events.include?(event_name_or_listener)
|
57
|
-
|
58
|
-
raise Errors::UnregisteredMonitorEventError, event_name_or_listener
|
59
|
-
end
|
60
|
-
|
61
|
-
# @return [Array<String>] names of available events to which we can subscribe
|
62
|
-
def available_events
|
63
|
-
__bus__.events.keys
|
5
|
+
# Karafka instrumentation monitor that we use to publish events
|
6
|
+
# By default uses our internal notifications bus but can be used with
|
7
|
+
# `ActiveSupport::Notifications` as well
|
8
|
+
class Monitor < ::Karafka::Core::Monitoring::Monitor
|
9
|
+
attr_reader :notifications_bus
|
10
|
+
|
11
|
+
# @param notifications_bus [Object] either our internal notifications bus or
|
12
|
+
# `ActiveSupport::Notifications`
|
13
|
+
# @param namespace [String, nil] namespace for events or nil if no namespace
|
14
|
+
def initialize(
|
15
|
+
notifications_bus = ::Karafka::Instrumentation::Notifications.new,
|
16
|
+
namespace = nil
|
17
|
+
)
|
18
|
+
super(notifications_bus, namespace)
|
64
19
|
end
|
65
20
|
end
|
66
21
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
# Namespace for all the things related with Karafka instrumentation process
|
5
|
+
module Instrumentation
|
6
|
+
# Monitor is used to hookup external monitoring services to monitor how Karafka works
|
7
|
+
# It provides a standardized API for checking incoming messages/enqueueing etc
|
8
|
+
# Since it is a pub-sub based on dry-monitor, you can use as many subscribers/loggers at the
|
9
|
+
# same time, which means that you might have for example file logging and NewRelic at the same
|
10
|
+
# time
|
11
|
+
# @note This class acts as a singleton because we are only permitted to have single monitor
|
12
|
+
# per running process (just as logger)
|
13
|
+
class Notifications < Karafka::Core::Monitoring::Notifications
|
14
|
+
# List of events that we support in the system and to which a monitor client can hook up
|
15
|
+
# @note The non-error once support timestamp benchmarking
|
16
|
+
# @note Depending on Karafka extensions and additional engines, this might not be the
|
17
|
+
# complete list of all the events. Please use the #available_events on fully loaded
|
18
|
+
# Karafka system to determine all of the events you can use.
|
19
|
+
EVENTS = %w[
|
20
|
+
app.initialized
|
21
|
+
app.running
|
22
|
+
app.stopping
|
23
|
+
app.stopped
|
24
|
+
|
25
|
+
consumer.consumed
|
26
|
+
consumer.revoked
|
27
|
+
consumer.shutdown
|
28
|
+
|
29
|
+
process.notice_signal
|
30
|
+
|
31
|
+
connection.listener.before_fetch_loop
|
32
|
+
connection.listener.fetch_loop
|
33
|
+
connection.listener.fetch_loop.received
|
34
|
+
|
35
|
+
worker.process
|
36
|
+
worker.processed
|
37
|
+
|
38
|
+
statistics.emitted
|
39
|
+
|
40
|
+
error.occurred
|
41
|
+
].freeze
|
42
|
+
|
43
|
+
private_constant :EVENTS
|
44
|
+
|
45
|
+
# @return [Karafka::Instrumentation::Monitor] monitor instance for system instrumentation
|
46
|
+
def initialize
|
47
|
+
super
|
48
|
+
EVENTS.each { |event| register_event(event) }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|