karafka 2.0.0.beta4 → 2.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/workflows/ci.yml +18 -1
  4. data/CHANGELOG.md +30 -0
  5. data/CONTRIBUTING.md +0 -5
  6. data/Gemfile.lock +12 -42
  7. data/README.md +2 -12
  8. data/bin/benchmarks +2 -2
  9. data/bin/integrations +10 -3
  10. data/bin/{stress → stress_many} +1 -1
  11. data/bin/stress_one +13 -0
  12. data/config/errors.yml +48 -5
  13. data/docker-compose.yml +27 -18
  14. data/karafka.gemspec +2 -4
  15. data/lib/karafka/active_job/job_options_contract.rb +8 -2
  16. data/lib/karafka/active_job/routing/extensions.rb +1 -1
  17. data/lib/karafka/app.rb +2 -1
  18. data/lib/karafka/base_consumer.rb +24 -19
  19. data/lib/karafka/cli/install.rb +15 -2
  20. data/lib/karafka/cli/server.rb +4 -2
  21. data/lib/karafka/connection/client.rb +40 -17
  22. data/lib/karafka/connection/listener.rb +37 -11
  23. data/lib/karafka/connection/rebalance_manager.rb +20 -19
  24. data/lib/karafka/contracts/base.rb +2 -8
  25. data/lib/karafka/contracts/config.rb +71 -38
  26. data/lib/karafka/contracts/consumer_group.rb +25 -18
  27. data/lib/karafka/contracts/consumer_group_topic.rb +30 -16
  28. data/lib/karafka/contracts/server_cli_options.rb +18 -7
  29. data/lib/karafka/errors.rb +3 -0
  30. data/lib/karafka/helpers/colorize.rb +20 -0
  31. data/lib/karafka/pro/active_job/consumer.rb +1 -8
  32. data/lib/karafka/pro/active_job/job_options_contract.rb +10 -6
  33. data/lib/karafka/pro/base_consumer.rb +27 -21
  34. data/lib/karafka/pro/loader.rb +13 -6
  35. data/lib/karafka/pro/processing/coordinator.rb +63 -0
  36. data/lib/karafka/pro/processing/jobs_builder.rb +3 -2
  37. data/lib/karafka/pro/processing/partitioner.rb +41 -0
  38. data/lib/karafka/pro/processing/scheduler.rb +56 -0
  39. data/lib/karafka/pro/routing/extensions.rb +6 -0
  40. data/lib/karafka/processing/coordinator.rb +88 -0
  41. data/lib/karafka/processing/coordinators_buffer.rb +54 -0
  42. data/lib/karafka/processing/executor.rb +7 -17
  43. data/lib/karafka/processing/executors_buffer.rb +46 -15
  44. data/lib/karafka/processing/jobs/consume.rb +4 -2
  45. data/lib/karafka/processing/jobs_builder.rb +3 -2
  46. data/lib/karafka/processing/partitioner.rb +22 -0
  47. data/lib/karafka/processing/result.rb +0 -5
  48. data/lib/karafka/processing/scheduler.rb +22 -0
  49. data/lib/karafka/routing/consumer_group.rb +1 -1
  50. data/lib/karafka/routing/topic.rb +9 -0
  51. data/lib/karafka/setup/config.rb +26 -12
  52. data/lib/karafka/templates/example_consumer.rb.erb +2 -2
  53. data/lib/karafka/version.rb +1 -1
  54. data/lib/karafka.rb +0 -2
  55. data.tar.gz.sig +0 -0
  56. metadata +15 -36
  57. metadata.gz.sig +0 -0
  58. data/lib/karafka/pro/scheduler.rb +0 -54
  59. data/lib/karafka/scheduler.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4e9430d2278617cbed38f5696011603d9c0d8c53813dfc180499dc6e4b97563
4
- data.tar.gz: f082a95aa9841912f819dc0598591c4b96d7ef1199eff324e65ca0c601008dae
3
+ metadata.gz: f4103f2661316cc4e24aab8bf9715472c04f6911b3e56bb3ecdab775a0e32139
4
+ data.tar.gz: 0174d1cd163ac4fd046e4d432c0a4e2a07e2d57494ada9846ec61b6c73c2e434
5
5
  SHA512:
6
- metadata.gz: 7252c5503234ab4d35fa02d2bb0a18dd8239584fdddc5b451cfdf028a61f37d59a269bac804913d0abf46e2d3273188560e48aa9de40fbb319c766624c1a3b95
7
- data.tar.gz: a4cc5d7c18d2a45483ee26acbacf62c9c13f8824697af96a3f2bf5bccb232d5b07097ed49cfb84a9b46e09f31405813d50b1564d6668f0a483023f449427428b
6
+ metadata.gz: b3214a7e89730e932dbfbd3e5463ab0ce592d06589b5940f0987ded07f738d1f13557ae1d8251d8971beae7334c91bc655a8f64dd83049520d7ca889b2519e69
7
+ data.tar.gz: 803ae22e05ad14025dc4bda185571c586727227154e201d979052223b8270b157d7bd8a9588c0aa074c9d5bf0ef31dba6a1a696c7c392171c585945343d2fd10
checksums.yaml.gz.sig CHANGED
Binary file
@@ -8,6 +8,10 @@ on:
8
8
  schedule:
9
9
  - cron: '0 1 * * *'
10
10
 
11
+ env:
12
+ BUNDLE_RETRY: 6
13
+ BUNDLE_JOBS: 4
14
+
11
15
  jobs:
12
16
  diffend:
13
17
  runs-on: ubuntu-latest
@@ -17,13 +21,16 @@ jobs:
17
21
  - uses: actions/checkout@v2
18
22
  with:
19
23
  fetch-depth: 0
24
+
20
25
  - name: Set up Ruby
21
26
  uses: ruby/setup-ruby@v1
22
27
  with:
23
28
  ruby-version: 3.1
24
29
  bundler-cache: true
30
+
25
31
  - name: Install Diffend plugin
26
32
  run: bundle plugin install diffend
33
+
27
34
  - name: Bundle Secure
28
35
  run: bundle secure
29
36
 
@@ -101,7 +108,17 @@ jobs:
101
108
  uses: ruby/setup-ruby@v1
102
109
  with:
103
110
  ruby-version: ${{matrix.ruby}}
104
- bundler-cache: true
111
+
112
+ - name: Install latest Bundler
113
+ run: |
114
+ gem install bundler --no-document
115
+ gem update --system --no-document
116
+ bundle config set without 'tools benchmarks docs'
117
+
118
+ - name: Bundle install
119
+ run: |
120
+ bundle config set without development
121
+ bundle install
105
122
 
106
123
  - name: Ensure all needed Kafka topics are created and wait if not
107
124
  run: |
data/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Karafka framework changelog
2
2
 
3
+ ## 2.0.0.rc2 (2022-07-19)
4
+ - Fix `example_consumer.rb.erb` `#shutdown` and `#revoked` signatures to correct once.
5
+ - Improve the install user experience (print status and created files).
6
+ - Change default `max_wait_time` from 10s to 5s.
7
+ - Remove direct dependency on `dry-configurable` in favour of a home-brew.
8
+ - Remove direct dependency on `dry-validation` in favour of a home-brew.
9
+
10
+ ## 2.0.0-rc1 (2022-07-08)
11
+ - Extract consumption partitioner out of listener inline code.
12
+ - Introduce virtual partitioner concept for parallel processing of data from a single topic partition.
13
+ - Improve stability when there kafka internal errors occur while polling.
14
+ - Fix a case where we would resume a LRJ partition upon rebalance where we would reclaim the partition while job was still running.
15
+ - Do not revoke pauses for lost partitions. This will allow to un-pause reclaimed partitions when LRJ jobs are done.
16
+ - Fail integrations by default (unless configured otherwise) if any errors occur during Karafka server execution.
17
+
18
+ ## 2.0.0-beta5 (2022-07-05)
19
+ - Always resume processing of a revoked partition upon assignment.
20
+ - Improve specs stability.
21
+ - Fix a case where revocation job would be executed on partition for which we never did any work.
22
+ - Introduce a jobs group coordinator for easier jobs management.
23
+ - Improve stability of resuming paused partitions that were revoked and re-assigned.
24
+ - Optimize reaction time on partition ownership changes.
25
+ - Fix a bug where despite setting long max wait time, we would return messages prior to it while not reaching the desired max messages count.
26
+ - Add more integration specs related to polling limits.
27
+ - Remove auto-detection of re-assigned partitions upon rebalance as for too fast rebalances it could not be accurate enough. It would also mess up in case of rebalances that would happen right after a `#seek` was issued for a partition.
28
+ - Optimize the removal of pre-buffered lost partitions data.
29
+ - Always rune `#revoked` when rebalance with revocation happens.
30
+ - Evict executors upon rebalance, to prevent race-conditions.
31
+ - Align topics names for integration specs.
32
+
3
33
  ## 2.0.0-beta4 (2022-06-20)
4
34
  - Rename job internal api methods from `#prepare` to `#before_call` and from `#teardown` to `#after_call` to abstract away jobs execution from any type of executors and consumers logic
5
35
  - Remove ability of running `before_consume` and `after_consume` completely. Those should be for internal usage only.
data/CONTRIBUTING.md CHANGED
@@ -34,8 +34,3 @@ By sending a pull request to the pro components, you are agreeing to transfer th
34
34
 
35
35
  If you have any questions, create an [issue](issue) (protip: do a quick search first to see if someone else didn't ask the same question before!).
36
36
  You can also reach us at hello@karafka.opencollective.com.
37
-
38
- ## Credits
39
-
40
- Thank you to all the people who have already contributed to karafka!
41
- <a href="graphs/contributors"><img src="https://opencollective.com/karafka/contributors.svg?width=890" /></a>
data/Gemfile.lock CHANGED
@@ -1,22 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka (2.0.0.beta4)
5
- dry-configurable (~> 0.13)
4
+ karafka (2.0.0.rc2)
6
5
  dry-monitor (~> 0.5)
7
- dry-validation (~> 1.7)
8
6
  rdkafka (>= 0.10)
9
7
  thor (>= 0.20)
10
- waterdrop (>= 2.3.1, < 3.0.0)
8
+ waterdrop (>= 2.3.3, < 3.0.0)
11
9
  zeitwerk (~> 2.3)
12
10
 
13
11
  GEM
14
12
  remote: https://rubygems.org/
15
13
  specs:
16
- activejob (7.0.3)
17
- activesupport (= 7.0.3)
14
+ activejob (7.0.3.1)
15
+ activesupport (= 7.0.3.1)
18
16
  globalid (>= 0.3.6)
19
- activesupport (7.0.3)
17
+ activesupport (7.0.3.1)
20
18
  concurrent-ruby (~> 1.0, >= 1.0.2)
21
19
  i18n (>= 1.6, < 2)
22
20
  minitest (>= 5.1)
@@ -28,51 +26,25 @@ GEM
28
26
  dry-configurable (0.15.0)
29
27
  concurrent-ruby (~> 1.0)
30
28
  dry-core (~> 0.6)
31
- dry-container (0.9.0)
32
- concurrent-ruby (~> 1.0)
33
- dry-configurable (~> 0.13, >= 0.13.0)
34
- dry-core (0.7.1)
29
+ dry-core (0.8.0)
35
30
  concurrent-ruby (~> 1.0)
36
31
  dry-events (0.3.0)
37
32
  concurrent-ruby (~> 1.0)
38
33
  dry-core (~> 0.5, >= 0.5)
39
- dry-inflector (0.2.1)
40
- dry-initializer (3.1.1)
41
- dry-logic (1.2.0)
42
- concurrent-ruby (~> 1.0)
43
- dry-core (~> 0.5, >= 0.5)
44
- dry-monitor (0.5.0)
34
+ dry-monitor (0.6.1)
45
35
  dry-configurable (~> 0.13, >= 0.13.0)
46
36
  dry-core (~> 0.5, >= 0.5)
47
37
  dry-events (~> 0.2)
48
- dry-schema (1.9.2)
49
- concurrent-ruby (~> 1.0)
50
- dry-configurable (~> 0.13, >= 0.13.0)
51
- dry-core (~> 0.5, >= 0.5)
52
- dry-initializer (~> 3.0)
53
- dry-logic (~> 1.0)
54
- dry-types (~> 1.5)
55
- dry-types (1.5.1)
56
- concurrent-ruby (~> 1.0)
57
- dry-container (~> 0.3)
58
- dry-core (~> 0.5, >= 0.5)
59
- dry-inflector (~> 0.1, >= 0.1.2)
60
- dry-logic (~> 1.0, >= 1.0.2)
61
- dry-validation (1.8.1)
62
- concurrent-ruby (~> 1.0)
63
- dry-container (~> 0.7, >= 0.7.1)
64
- dry-core (~> 0.5, >= 0.5)
65
- dry-initializer (~> 3.0)
66
- dry-schema (~> 1.8, >= 1.8.0)
38
+ zeitwerk (~> 2.5)
67
39
  factory_bot (6.2.1)
68
40
  activesupport (>= 5.0.0)
69
41
  ffi (1.15.5)
70
42
  globalid (1.0.0)
71
43
  activesupport (>= 5.0)
72
- i18n (1.10.0)
44
+ i18n (1.12.0)
73
45
  concurrent-ruby (~> 1.0)
74
46
  mini_portile2 (2.8.0)
75
- minitest (5.15.0)
47
+ minitest (5.16.2)
76
48
  rake (13.0.6)
77
49
  rdkafka (0.12.0)
78
50
  ffi (~> 1.15)
@@ -100,11 +72,9 @@ GEM
100
72
  thor (1.2.1)
101
73
  tzinfo (2.0.4)
102
74
  concurrent-ruby (~> 1.0)
103
- waterdrop (2.3.1)
75
+ waterdrop (2.3.3)
104
76
  concurrent-ruby (>= 1.1)
105
- dry-configurable (~> 0.13)
106
77
  dry-monitor (~> 0.5)
107
- dry-validation (~> 1.7)
108
78
  rdkafka (>= 0.10)
109
79
  zeitwerk (~> 2.3)
110
80
  zeitwerk (2.6.0)
@@ -121,4 +91,4 @@ DEPENDENCIES
121
91
  simplecov
122
92
 
123
93
  BUNDLED WITH
124
- 2.3.11
94
+ 2.3.15
data/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ## About Karafka
10
10
 
11
- Karafka is a framework used to simplify Apache Kafka based Ruby and Ruby on Rails applications development.
11
+ Karafka is a multi-threaded framework used to simplify Apache Kafka based Ruby and Ruby on Rails applications development.
12
12
 
13
13
  ```ruby
14
14
  # Define what topics you want to consume with which consumers in karafka.rb
@@ -28,8 +28,6 @@ class EventsConsumer < ApplicationConsumer
28
28
  end
29
29
  ```
30
30
 
31
- Karafka allows you to capture everything that happens in your systems in large scale, providing you with a seamless and stable core for consuming, processing and producing data, without having to focus on things that are not your business domain.
32
-
33
31
  Karafka **uses** threads to handle many messages at the same time 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.
34
32
 
35
33
  ## Getting started
@@ -45,7 +43,7 @@ We also maintain many [integration specs](https://github.com/karafka/karafka/tre
45
43
 
46
44
  ## Want to Upgrade? LGPL is not for you? Want to help?
47
45
 
48
- I also sell Karafka Pro subscription. It includes commercial-friendly license, priority support, architecture consultations and high throughput data processing-related features (under development).
46
+ I also sell Karafka Pro subscription. It includes commercial-friendly license, priority support, architecture consultations and high throughput data processing-related features (virtual partitions, long running jobs and more).
49
47
 
50
48
  **20%** of the income will be distributed back to other OSS projects that Karafka uses under the hood.
51
49
 
@@ -56,11 +54,3 @@ Help me provide high-quality open-source software. Please see the Karafka [homep
56
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 whole installation, setup and deployment along with other useful details on how to run Karafka.
57
55
 
58
56
  If you have any questions about using Karafka, feel free to join our [Slack](https://slack.karafka.io) channel.
59
-
60
- ## Note on contributions
61
-
62
- First, thank you for considering contributing to the Karafka ecosystem! It's people like you that make the open source community such a great community!
63
-
64
- Each pull request must pass all the RSpec specs, integration tests and meet our quality requirements.
65
-
66
- Fork it, update and wait for the Github Actions results.
data/bin/benchmarks CHANGED
@@ -39,8 +39,8 @@ if ENV['SEED']
39
39
 
40
40
  # We do not populate data of benchmarks_0_10 as we use it with life-stream data only
41
41
  %w[
42
- benchmarks_0_01
43
- benchmarks_0_05
42
+ benchmarks_00_01
43
+ benchmarks_00_05
44
44
  ].each do |topic_name|
45
45
  partitions_count = topic_name.split('_').last.to_i
46
46
 
data/bin/integrations CHANGED
@@ -21,6 +21,9 @@ ROOT_PATH = Pathname.new(File.expand_path(File.join(File.dirname(__FILE__), '../
21
21
  # of CPU
22
22
  CONCURRENCY = ENV.key?('CI') ? 5 : Etc.nprocessors * 2
23
23
 
24
+ # How may bytes do we want to keep from the stdout in the buffer for when we need to print it
25
+ MAX_BUFFER_OUTPUT = 10_240
26
+
24
27
  # Abstraction around a single test scenario execution process
25
28
  class Scenario
26
29
  # How long a scenario can run before we kill it
@@ -84,9 +87,9 @@ class Scenario
84
87
  # We read it so it won't grow as we use our default logger that prints to both test.log and
85
88
  # to stdout. Otherwise after reaching the buffer size, it would hang
86
89
  buffer = ''
87
- @stdout.read_nonblock(10_240, buffer, exception: false)
90
+ @stdout.read_nonblock(MAX_BUFFER_OUTPUT, buffer, exception: false)
88
91
  @stdout_tail << buffer
89
- @stdout_tail = @stdout_tail[-10_024..-1] || @stdout_tail
92
+ @stdout_tail = @stdout_tail[-MAX_BUFFER_OUTPUT..-1] || @stdout_tail
90
93
 
91
94
  !@wait_thr.alive?
92
95
  end
@@ -114,11 +117,15 @@ class Scenario
114
117
  if success?
115
118
  print "\e[#{32}m#{'.'}\e[0m"
116
119
  else
120
+ buffer = ''
121
+
122
+ @stderr.read_nonblock(MAX_BUFFER_OUTPUT, buffer, exception: false)
123
+
117
124
  puts
118
125
  puts "\e[#{31}m#{'[FAILED]'}\e[0m #{name}"
119
126
  puts "Exit code: #{exit_code}"
120
127
  puts @stdout_tail
121
- puts @stderr.read
128
+ puts buffer
122
129
  puts
123
130
  end
124
131
  end
@@ -8,6 +8,6 @@ set -e
8
8
 
9
9
  while :
10
10
  do
11
- reset
11
+ clear
12
12
  bin/integrations $1
13
13
  done
data/bin/stress_one ADDED
@@ -0,0 +1,13 @@
1
+ #!/bin/bash
2
+
3
+ # Runs a single integration spec in an endless loop
4
+ # This allows us to ensure (after long enough time) that the integration spec is stable and
5
+ # that there are no anomalies when running it for a long period of time
6
+
7
+ set -e
8
+
9
+ while :
10
+ do
11
+ clear
12
+ bin/scenario $1
13
+ done
data/config/errors.yml CHANGED
@@ -1,9 +1,52 @@
1
1
  en:
2
- dry_validation:
3
- errors:
2
+ validations:
3
+ config:
4
+ missing: needs to be present
5
+ client_id_format: 'needs to be a string with a Kafka accepted format'
6
+ license.entity_format: needs to be a string
7
+ license.token_format: needs to be either false or a string
8
+ license.expires_on_format: needs to be a valid date
9
+ concurrency_format: needs to be an integer bigger than 0
10
+ consumer_mapper_format: needs to be present
11
+ consumer_persistence_format: needs to be either true or false
12
+ pause_timeout_format: needs to be an integer bigger than 0
13
+ pause_max_timeout_format: needs to be an integer bigger than 0
14
+ pause_with_exponential_backoff_format: needs to be either true or false
15
+ shutdown_timeout_format: needs to be an integer bigger than 0
16
+ max_wait_time_format: needs to be an integer bigger than 0
17
+ kafka_format: needs to be a filled hash
18
+ internal.status_format: needs to be present
19
+ internal.process_format: needs to be present
20
+ internal.routing.builder_format: needs to be present
21
+ internal.routing.subscription_groups_builder_format: needs to be present
22
+ key_must_be_a_symbol: All keys under the kafka settings scope need to be symbols
4
23
  max_timeout_vs_pause_max_timeout: pause_timeout must be less or equal to pause_max_timeout
5
24
  shutdown_timeout_vs_max_wait_time: shutdown_timeout must be more than max_wait_time
6
- topics_names_not_unique: all topic names within a single consumer group must be unique
7
- required_usage_count: Given topic must be used at least once
25
+
26
+ server_cli_options:
27
+ missing: needs to be present
8
28
  consumer_groups_inclusion: Unknown consumer group
9
- kafka_key_must_be_a_symbol: All keys under the kafka settings scope need to be symbols
29
+
30
+ consumer_group_topic:
31
+ missing: needs to be present
32
+ name_format: 'needs to be a string with a Kafka accepted format'
33
+ deserializer_format: needs to be present
34
+ manual_offset_management_format: needs to be either true or false
35
+ consumer_format: needs to be present
36
+ id_format: 'needs to be a string with a Kafka accepted format'
37
+ initial_offset_format: needs to be either earliest or latest
38
+
39
+ consumer_group:
40
+ missing: needs to be present
41
+ topics_names_not_unique: all topic names within a single consumer group must be unique
42
+ id_format: 'needs to be a string with a Kafka accepted format'
43
+ topics_format: needs to be a non-empty array
44
+
45
+ job_options:
46
+ missing: needs to be present
47
+ dispatch_method_format: needs to be either :produce_async or :produce_sync
48
+ partitioner_format: 'needs to respond to #call'
49
+
50
+ test:
51
+ missing: needs to be present
52
+ id_format: needs to be a String
data/docker-compose.yml CHANGED
@@ -16,26 +16,35 @@ services:
16
16
  KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
17
17
  KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'true'
18
18
  KAFKA_CREATE_TOPICS:
19
- "integrations_0_02:2:1,\
20
- integrations_1_02:2:1,\
21
- integrations_2_02:2:1,\
22
- integrations_3_02:2:1,\
23
- integrations_4_02:2:1,\
24
- integrations_5_02:2:1,\
25
- integrations_6_02:2:1,\
26
- integrations_7_02:2:1,\
27
- integrations_8_02:2:1,\
28
- integrations_9_02:2:1,\
19
+ "integrations_00_02:2:1,\
20
+ integrations_01_02:2:1,\
21
+ integrations_02_02:2:1,\
22
+ integrations_03_02:2:1,\
23
+ integrations_04_02:2:1,\
24
+ integrations_05_02:2:1,\
25
+ integrations_06_02:2:1,\
26
+ integrations_07_02:2:1,\
27
+ integrations_08_02:2:1,\
28
+ integrations_09_02:2:1,\
29
29
  integrations_10_02:2:1,\
30
30
  integrations_11_02:2:1,\
31
31
  integrations_12_02:2:1,\
32
- integrations_0_03:3:1,\
33
- integrations_1_03:3:1,\
34
- integrations_2_03:3:1,\
35
- integrations_0_10:10:1,\
36
- integrations_1_10:10:1,\
37
- benchmarks_0_01:1:1,\
38
- benchmarks_0_05:5:1,\
39
- benchmarks_0_10:10:1"
32
+ integrations_13_02:2:1,\
33
+ integrations_14_02:2:1,\
34
+ integrations_15_02:2:1,\
35
+ integrations_16_02:2:1,\
36
+ integrations_17_02:2:1,\
37
+ integrations_18_02:2:1,\
38
+ integrations_19_02:2:1,\
39
+ integrations_00_03:3:1,\
40
+ integrations_01_03:3:1,\
41
+ integrations_02_03:3:1,\
42
+ integrations_03_03:3:1,\
43
+ integrations_00_10:10:1,\
44
+ integrations_01_10:10:1,\
45
+ benchmarks_00_01:1:1,\
46
+ benchmarks_00_05:5:1,\
47
+ benchmarks_01_05:5:1,\
48
+ benchmarks_00_10:10:1"
40
49
  volumes:
41
50
  - /var/run/docker.sock:/var/run/docker.sock
data/karafka.gemspec CHANGED
@@ -12,16 +12,14 @@ 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 = 'Ruby based framework for working with Apache Kafka'
15
+ spec.summary = 'Ruby framework for working with Apache Kafka'
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 'dry-configurable', '~> 0.13'
20
19
  spec.add_dependency 'dry-monitor', '~> 0.5'
21
- spec.add_dependency 'dry-validation', '~> 1.7'
22
20
  spec.add_dependency 'rdkafka', '>= 0.10'
23
21
  spec.add_dependency 'thor', '>= 0.20'
24
- spec.add_dependency 'waterdrop', '>= 2.3.1', '< 3.0.0'
22
+ spec.add_dependency 'waterdrop', '>= 2.3.3', '< 3.0.0'
25
23
  spec.add_dependency 'zeitwerk', '~> 2.3'
26
24
 
27
25
  spec.required_ruby_version = '>= 2.6.0'
@@ -7,9 +7,15 @@ module Karafka
7
7
  # we want to keep ActiveJob related Karafka components outside of the core Karafka code and
8
8
  # all in the same place
9
9
  class JobOptionsContract < Contracts::Base
10
- params do
11
- optional(:dispatch_method).value(included_in?: %i[produce_async produce_sync])
10
+ configure do |config|
11
+ config.error_messages = YAML.safe_load(
12
+ File.read(
13
+ File.join(Karafka.gem_root, 'config', 'errors.yml')
14
+ )
15
+ ).fetch('en').fetch('validations').fetch('job_options')
12
16
  end
17
+
18
+ optional(:dispatch_method) { |val| %i[produce_async produce_sync].include?(val) }
13
19
  end
14
20
  end
15
21
  end
@@ -13,7 +13,7 @@ module Karafka
13
13
  # @param block [Proc] block that we can use for some extra configuration
14
14
  def active_job_topic(name, &block)
15
15
  topic(name) do
16
- consumer App.config.internal.active_job.consumer
16
+ consumer App.config.internal.active_job.consumer_class
17
17
 
18
18
  next unless block
19
19
 
data/lib/karafka/app.rb CHANGED
@@ -10,7 +10,8 @@ module Karafka
10
10
  def consumer_groups
11
11
  config
12
12
  .internal
13
- .routing_builder
13
+ .routing
14
+ .builder
14
15
  end
15
16
 
16
17
  # @return [Array<Karafka::Routing::SubscriptionGroup>] active subscription groups
@@ -10,17 +10,11 @@ module Karafka
10
10
  attr_accessor :messages
11
11
  # @return [Karafka::Connection::Client] kafka connection client
12
12
  attr_accessor :client
13
- # @return [Karafka::TimeTrackers::Pause] current topic partition pause tracker
14
- attr_accessor :pause_tracker
13
+ # @return [Karafka::Processing::Coordinator] coordinator
14
+ attr_accessor :coordinator
15
15
  # @return [Waterdrop::Producer] producer instance
16
16
  attr_accessor :producer
17
17
 
18
- def initialize
19
- # We re-use one to save on object allocation
20
- # It also allows us to transfer the consumption notion to another batch
21
- @consumption = Processing::Result.new
22
- end
23
-
24
18
  # Can be used to run preparation code
25
19
  #
26
20
  # @private
@@ -41,9 +35,9 @@ module Karafka
41
35
  consume
42
36
  end
43
37
 
44
- @consumption.success!
38
+ coordinator.consumption(self).success!
45
39
  rescue StandardError => e
46
- @consumption.failure!
40
+ coordinator.consumption(self).failure!
47
41
 
48
42
  Karafka.monitor.instrument(
49
43
  'error.occurred',
@@ -51,14 +45,19 @@ module Karafka
51
45
  caller: self,
52
46
  type: 'consumer.consume.error'
53
47
  )
48
+ ensure
49
+ # We need to decrease number of jobs that this coordinator coordinates as it has finished
50
+ coordinator.decrement
54
51
  end
55
52
 
56
53
  # @private
57
54
  # @note This should not be used by the end users as it is part of the lifecycle of things but
58
55
  # not as part of the public api.
59
56
  def on_after_consume
60
- if @consumption.success?
61
- pause_tracker.reset
57
+ return if revoked?
58
+
59
+ if coordinator.success?
60
+ coordinator.pause_tracker.reset
62
61
 
63
62
  # Mark as consumed only if manual offset management is not on
64
63
  return if topic.manual_offset_management?
@@ -75,6 +74,8 @@ module Karafka
75
74
  #
76
75
  # @private
77
76
  def on_revoked
77
+ coordinator.revoke
78
+
78
79
  Karafka.monitor.instrument('consumer.revoked', caller: self) do
79
80
  revoked
80
81
  end
@@ -132,9 +133,11 @@ module Karafka
132
133
  # processed but rather at the next one. This applies to both sync and async versions of this
133
134
  # method.
134
135
  def mark_as_consumed(message)
135
- @revoked = !client.mark_as_consumed(message)
136
+ unless client.mark_as_consumed(message)
137
+ coordinator.revoke
136
138
 
137
- return false if revoked?
139
+ return false
140
+ end
138
141
 
139
142
  @seek_offset = message.offset + 1
140
143
 
@@ -147,9 +150,11 @@ module Karafka
147
150
  # @return [Boolean] true if we were able to mark the offset, false otherwise. False indicates
148
151
  # that we were not able and that we have lost the partition.
149
152
  def mark_as_consumed!(message)
150
- @revoked = !client.mark_as_consumed!(message)
153
+ unless client.mark_as_consumed!(message)
154
+ coordinator.revoke
151
155
 
152
- return false if revoked?
156
+ return false
157
+ end
153
158
 
154
159
  @seek_offset = message.offset + 1
155
160
 
@@ -163,7 +168,7 @@ module Karafka
163
168
  # @param timeout [Integer, nil] how long in milliseconds do we want to pause or nil to use the
164
169
  # default exponential pausing strategy defined for retries
165
170
  def pause(offset, timeout = nil)
166
- timeout ? pause_tracker.pause(timeout) : pause_tracker.pause
171
+ timeout ? coordinator.pause_tracker.pause(timeout) : coordinator.pause_tracker.pause
167
172
 
168
173
  client.pause(
169
174
  messages.metadata.topic,
@@ -176,7 +181,7 @@ module Karafka
176
181
  def resume
177
182
  # This is sufficient to expire a partition pause, as with it will be resumed by the listener
178
183
  # thread before the next poll.
179
- pause_tracker.expire
184
+ coordinator.pause_tracker.expire
180
185
  end
181
186
 
182
187
  # Seeks in the context of current topic and partition
@@ -196,7 +201,7 @@ module Karafka
196
201
  # @note We know that partition got revoked because when we try to mark message as consumed,
197
202
  # unless if is successful, it will return false
198
203
  def revoked?
199
- @revoked || false
204
+ coordinator.revoked?
200
205
  end
201
206
  end
202
207
  end
@@ -7,6 +7,8 @@ module Karafka
7
7
  class Cli < Thor
8
8
  # Install Karafka Cli action
9
9
  class Install < Base
10
+ include Helpers::Colorize
11
+
10
12
  desc 'Install all required things for Karafka application in current directory'
11
13
 
12
14
  # Directories created by default
@@ -42,14 +44,25 @@ module Karafka
42
44
  FileUtils.mkdir_p Karafka.root.join(dir)
43
45
  end
44
46
 
47
+ puts
48
+ puts 'Installing Karafka framework...'
49
+ puts 'Ruby on Rails detected...' if rails?
50
+ puts
51
+
45
52
  INSTALL_FILES_MAP.each do |source, target|
46
- target = Karafka.root.join(target)
53
+ pathed_target = Karafka.root.join(target)
47
54
 
48
55
  template = File.read(Karafka.core_root.join("templates/#{source}"))
49
56
  render = ::ERB.new(template, trim_mode: '-').result(binding)
50
57
 
51
- File.open(target, 'w') { |file| file.write(render) }
58
+ File.open(pathed_target, 'w') { |file| file.write(render) }
59
+
60
+ puts "#{green('Created')} #{target}"
52
61
  end
62
+
63
+ puts
64
+ puts("Installation #{green('completed')}. Have fun!")
65
+ puts
53
66
  end
54
67
 
55
68
  # @return [Boolean] true if we have Rails loaded