karafka 2.4.0 → 2.4.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +26 -34
- data/.github/workflows/ci.yml +18 -6
- data/.ruby-version +1 -1
- data/CHANGELOG.md +146 -1
- data/Gemfile +10 -5
- data/Gemfile.lock +60 -39
- data/LICENSE +8 -3
- data/bin/integrations +13 -1
- data/certs/cert.pem +26 -0
- data/config/locales/errors.yml +18 -2
- data/config/locales/pro_errors.yml +44 -0
- data/docker-compose.yml +1 -3
- data/karafka.gemspec +6 -4
- data/lib/active_job/queue_adapters/karafka_adapter.rb +18 -7
- data/lib/karafka/active_job/dispatcher.rb +13 -0
- data/lib/karafka/active_job/job_extensions.rb +3 -0
- data/lib/karafka/admin.rb +86 -0
- data/lib/karafka/app.rb +17 -0
- data/lib/karafka/base_consumer.rb +130 -19
- data/lib/karafka/cli/base.rb +24 -8
- data/lib/karafka/cli/install.rb +2 -1
- data/lib/karafka/cli/server.rb +1 -0
- data/lib/karafka/cli/swarm.rb +1 -0
- data/lib/karafka/cli/topics/align.rb +12 -2
- data/lib/karafka/cli/topics/plan.rb +54 -6
- data/lib/karafka/cli/topics.rb +45 -18
- data/lib/karafka/connection/client.rb +102 -35
- data/lib/karafka/connection/listener.rb +48 -11
- data/lib/karafka/connection/messages_buffer.rb +19 -6
- data/lib/karafka/connection/proxy.rb +3 -0
- data/lib/karafka/connection/raw_messages_buffer.rb +43 -9
- data/lib/karafka/connection/rebalance_manager.rb +24 -13
- data/lib/karafka/contracts/config.rb +4 -0
- data/lib/karafka/contracts/consumer_group.rb +17 -0
- data/lib/karafka/contracts/routing.rb +59 -0
- data/lib/karafka/contracts/topic.rb +14 -0
- data/lib/karafka/embedded.rb +46 -3
- data/lib/karafka/errors.rb +3 -2
- data/lib/karafka/helpers/async.rb +11 -2
- data/lib/karafka/helpers/config_importer.rb +13 -0
- data/lib/karafka/instrumentation/assignments_tracker.rb +7 -2
- data/lib/karafka/instrumentation/logger_listener.rb +45 -4
- data/lib/karafka/instrumentation/notifications.rb +12 -0
- data/lib/karafka/instrumentation/vendors/appsignal/client.rb +32 -11
- data/lib/karafka/instrumentation/vendors/appsignal/errors_listener.rb +1 -1
- data/lib/karafka/instrumentation/vendors/appsignal/metrics_listener.rb +3 -1
- data/lib/karafka/instrumentation/vendors/datadog/logger_listener.rb +17 -19
- data/lib/karafka/instrumentation/vendors/datadog/metrics_listener.rb +27 -18
- data/lib/karafka/instrumentation/vendors/kubernetes/base_listener.rb +2 -2
- data/lib/karafka/instrumentation/vendors/kubernetes/liveness_listener.rb +41 -13
- data/lib/karafka/messages/message.rb +9 -9
- data/lib/karafka/pro/active_job/consumer.rb +2 -10
- data/lib/karafka/pro/active_job/dispatcher.rb +67 -19
- data/lib/karafka/pro/active_job/job_options_contract.rb +12 -10
- data/lib/karafka/pro/base_consumer.rb +2 -10
- data/lib/karafka/pro/cleaner/errors.rb +2 -10
- data/lib/karafka/pro/cleaner/messages/message.rb +14 -12
- data/lib/karafka/pro/cleaner/messages/messages.rb +2 -10
- data/lib/karafka/pro/cleaner/messages/metadata.rb +41 -0
- data/lib/karafka/pro/cleaner.rb +3 -10
- data/lib/karafka/pro/connection/manager.rb +6 -10
- data/lib/karafka/pro/connection/multiplexing/listener.rb +2 -10
- data/lib/karafka/pro/contracts/base.rb +2 -10
- data/lib/karafka/pro/contracts/server_cli_options.rb +2 -10
- data/lib/karafka/pro/encryption/cipher.rb +2 -10
- data/lib/karafka/pro/encryption/contracts/config.rb +2 -10
- data/lib/karafka/pro/encryption/errors.rb +2 -10
- data/lib/karafka/pro/encryption/messages/middleware.rb +2 -10
- data/lib/karafka/pro/encryption/messages/parser.rb +2 -10
- data/lib/karafka/pro/encryption/setup/config.rb +2 -10
- data/lib/karafka/pro/encryption.rb +2 -10
- data/lib/karafka/pro/instrumentation/performance_tracker.rb +2 -10
- data/lib/karafka/pro/iterator/expander.rb +2 -10
- data/lib/karafka/pro/iterator/tpl_builder.rb +2 -10
- data/lib/karafka/pro/iterator.rb +2 -10
- data/lib/karafka/pro/loader.rb +5 -11
- data/lib/karafka/pro/processing/adaptive_iterator/consumer.rb +54 -0
- data/lib/karafka/pro/processing/adaptive_iterator/tracker.rb +67 -0
- data/lib/karafka/pro/processing/collapser.rb +2 -10
- data/lib/karafka/pro/processing/coordinator.rb +2 -10
- data/lib/karafka/pro/processing/coordinators/errors_tracker.rb +2 -10
- data/lib/karafka/pro/processing/coordinators/filters_applier.rb +19 -10
- data/lib/karafka/pro/processing/coordinators/virtual_offset_manager.rb +2 -10
- data/lib/karafka/pro/processing/executor.rb +2 -10
- data/lib/karafka/pro/processing/expansions_selector.rb +3 -10
- data/lib/karafka/pro/processing/filters/base.rb +14 -10
- data/lib/karafka/pro/processing/filters/delayer.rb +4 -12
- data/lib/karafka/pro/processing/filters/expirer.rb +2 -10
- data/lib/karafka/pro/processing/filters/inline_insights_delayer.rb +2 -10
- data/lib/karafka/pro/processing/filters/throttler.rb +2 -10
- data/lib/karafka/pro/processing/filters/virtual_limiter.rb +2 -10
- data/lib/karafka/pro/processing/jobs/consume_non_blocking.rb +4 -10
- data/lib/karafka/pro/processing/jobs/eofed_non_blocking.rb +26 -0
- data/lib/karafka/pro/processing/jobs/periodic.rb +4 -10
- data/lib/karafka/pro/processing/jobs/periodic_non_blocking.rb +4 -10
- data/lib/karafka/pro/processing/jobs/revoked_non_blocking.rb +4 -10
- data/lib/karafka/pro/processing/jobs_builder.rb +14 -10
- data/lib/karafka/pro/processing/jobs_queue.rb +2 -10
- data/lib/karafka/pro/processing/offset_metadata/consumer.rb +2 -10
- data/lib/karafka/pro/processing/offset_metadata/fetcher.rb +2 -10
- data/lib/karafka/pro/processing/offset_metadata/listener.rb +2 -10
- data/lib/karafka/pro/processing/partitioner.rb +35 -24
- data/lib/karafka/pro/processing/periodic_job/consumer.rb +2 -10
- data/lib/karafka/pro/processing/piping/consumer.rb +2 -10
- data/lib/karafka/pro/processing/schedulers/base.rb +2 -10
- data/lib/karafka/pro/processing/schedulers/default.rb +3 -10
- data/lib/karafka/pro/processing/strategies/aj/dlq_ftr_lrj_mom.rb +3 -11
- data/lib/karafka/pro/processing/strategies/aj/dlq_ftr_lrj_mom_vp.rb +3 -11
- data/lib/karafka/pro/processing/strategies/aj/dlq_ftr_mom.rb +2 -10
- data/lib/karafka/pro/processing/strategies/aj/dlq_ftr_mom_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/aj/dlq_lrj_mom.rb +3 -11
- data/lib/karafka/pro/processing/strategies/aj/dlq_lrj_mom_vp.rb +3 -11
- data/lib/karafka/pro/processing/strategies/aj/dlq_mom.rb +2 -10
- data/lib/karafka/pro/processing/strategies/aj/dlq_mom_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/aj/ftr_lrj_mom.rb +2 -10
- data/lib/karafka/pro/processing/strategies/aj/ftr_lrj_mom_vp.rb +3 -11
- data/lib/karafka/pro/processing/strategies/aj/ftr_mom.rb +2 -10
- data/lib/karafka/pro/processing/strategies/aj/ftr_mom_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/aj/lrj_mom.rb +2 -10
- data/lib/karafka/pro/processing/strategies/aj/lrj_mom_vp.rb +5 -13
- data/lib/karafka/pro/processing/strategies/aj/mom.rb +2 -10
- data/lib/karafka/pro/processing/strategies/aj/mom_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/base.rb +2 -10
- data/lib/karafka/pro/processing/strategies/default.rb +140 -58
- data/lib/karafka/pro/processing/strategies/dlq/default.rb +23 -15
- data/lib/karafka/pro/processing/strategies/dlq/ftr.rb +2 -10
- data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj.rb +3 -11
- data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj_mom.rb +7 -11
- data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj_mom_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/dlq/ftr_mom.rb +19 -11
- data/lib/karafka/pro/processing/strategies/dlq/ftr_mom_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/dlq/ftr_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/dlq/lrj.rb +3 -11
- data/lib/karafka/pro/processing/strategies/dlq/lrj_mom.rb +19 -11
- data/lib/karafka/pro/processing/strategies/dlq/lrj_mom_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/dlq/lrj_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/dlq/mom.rb +24 -16
- data/lib/karafka/pro/processing/strategies/dlq/mom_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/dlq/vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/ftr/default.rb +17 -12
- data/lib/karafka/pro/processing/strategies/ftr/vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/lrj/default.rb +5 -13
- data/lib/karafka/pro/processing/strategies/lrj/ftr.rb +3 -11
- data/lib/karafka/pro/processing/strategies/lrj/ftr_mom.rb +2 -10
- data/lib/karafka/pro/processing/strategies/lrj/ftr_mom_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/lrj/ftr_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/lrj/mom.rb +4 -12
- data/lib/karafka/pro/processing/strategies/lrj/mom_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/lrj/vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/mom/default.rb +2 -10
- data/lib/karafka/pro/processing/strategies/mom/ftr.rb +2 -10
- data/lib/karafka/pro/processing/strategies/mom/ftr_vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/mom/vp.rb +2 -10
- data/lib/karafka/pro/processing/strategies/vp/default.rb +5 -10
- data/lib/karafka/pro/processing/strategies.rb +2 -10
- data/lib/karafka/pro/processing/strategy_selector.rb +2 -10
- data/lib/karafka/pro/processing/subscription_groups_coordinator.rb +2 -10
- data/lib/karafka/pro/recurring_tasks/consumer.rb +97 -0
- data/lib/karafka/pro/recurring_tasks/contracts/config.rb +45 -0
- data/lib/karafka/pro/recurring_tasks/contracts/task.rb +33 -0
- data/lib/karafka/pro/recurring_tasks/deserializer.rb +27 -0
- data/lib/karafka/pro/recurring_tasks/dispatcher.rb +79 -0
- data/lib/karafka/pro/recurring_tasks/errors.rb +26 -0
- data/lib/karafka/pro/recurring_tasks/executor.rb +144 -0
- data/lib/karafka/pro/recurring_tasks/listener.rb +30 -0
- data/lib/karafka/pro/recurring_tasks/matcher.rb +30 -0
- data/lib/karafka/pro/recurring_tasks/schedule.rb +55 -0
- data/lib/karafka/pro/recurring_tasks/serializer.rb +105 -0
- data/lib/karafka/pro/recurring_tasks/setup/config.rb +44 -0
- data/lib/karafka/pro/recurring_tasks/task.rb +143 -0
- data/lib/karafka/pro/recurring_tasks.rb +79 -0
- data/lib/karafka/pro/routing/features/active_job/builder.rb +2 -10
- data/lib/karafka/pro/routing/features/active_job.rb +2 -10
- data/lib/karafka/pro/routing/features/adaptive_iterator/config.rb +26 -0
- data/lib/karafka/pro/routing/features/adaptive_iterator/contracts/topic.rb +66 -0
- data/lib/karafka/pro/routing/features/adaptive_iterator/topic.rb +54 -0
- data/lib/karafka/pro/routing/features/adaptive_iterator.rb +23 -0
- data/lib/karafka/pro/routing/features/base.rb +2 -10
- data/lib/karafka/pro/routing/features/dead_letter_queue/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/dead_letter_queue/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/dead_letter_queue.rb +2 -10
- data/lib/karafka/pro/routing/features/delaying/config.rb +2 -10
- data/lib/karafka/pro/routing/features/delaying/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/delaying/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/delaying.rb +2 -10
- data/lib/karafka/pro/routing/features/direct_assignments/config.rb +2 -10
- data/lib/karafka/pro/routing/features/direct_assignments/contracts/consumer_group.rb +2 -10
- data/lib/karafka/pro/routing/features/direct_assignments/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/direct_assignments/subscription_group.rb +2 -10
- data/lib/karafka/pro/routing/features/direct_assignments/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/direct_assignments.rb +2 -10
- data/lib/karafka/pro/routing/features/expiring/config.rb +2 -10
- data/lib/karafka/pro/routing/features/expiring/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/expiring/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/expiring.rb +2 -10
- data/lib/karafka/pro/routing/features/filtering/config.rb +2 -10
- data/lib/karafka/pro/routing/features/filtering/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/filtering/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/filtering.rb +2 -10
- data/lib/karafka/pro/routing/features/inline_insights/config.rb +2 -10
- data/lib/karafka/pro/routing/features/inline_insights/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/inline_insights/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/inline_insights.rb +2 -10
- data/lib/karafka/pro/routing/features/long_running_job/config.rb +2 -10
- data/lib/karafka/pro/routing/features/long_running_job/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/long_running_job/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/long_running_job.rb +2 -10
- data/lib/karafka/pro/routing/features/multiplexing/config.rb +2 -10
- data/lib/karafka/pro/routing/features/multiplexing/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/multiplexing/patches/contracts/consumer_group.rb +2 -10
- data/lib/karafka/pro/routing/features/multiplexing/proxy.rb +2 -10
- data/lib/karafka/pro/routing/features/multiplexing/subscription_group.rb +2 -10
- data/lib/karafka/pro/routing/features/multiplexing/subscription_groups_builder.rb +2 -10
- data/lib/karafka/pro/routing/features/multiplexing.rb +2 -10
- data/lib/karafka/pro/routing/features/non_blocking_job/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/non_blocking_job.rb +2 -10
- data/lib/karafka/pro/routing/features/offset_metadata/config.rb +2 -10
- data/lib/karafka/pro/routing/features/offset_metadata/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/offset_metadata/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/offset_metadata.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns/builder.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns/config.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns/consumer_group.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns/contracts/consumer_group.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns/contracts/pattern.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns/detector.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns/pattern.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns/patterns.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns/topics.rb +2 -10
- data/lib/karafka/pro/routing/features/patterns.rb +2 -10
- data/lib/karafka/pro/routing/features/pausing/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/pausing/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/pausing.rb +2 -10
- data/lib/karafka/pro/routing/features/periodic_job/config.rb +2 -10
- data/lib/karafka/pro/routing/features/periodic_job/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/periodic_job/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/periodic_job.rb +2 -10
- data/lib/karafka/pro/routing/features/recurring_tasks/builder.rb +123 -0
- data/lib/karafka/pro/routing/features/recurring_tasks/config.rb +20 -0
- data/lib/karafka/pro/routing/features/recurring_tasks/contracts/topic.rb +32 -0
- data/lib/karafka/pro/routing/features/recurring_tasks/proxy.rb +19 -0
- data/lib/karafka/pro/routing/features/recurring_tasks/topic.rb +36 -0
- data/lib/karafka/pro/routing/features/recurring_tasks.rb +17 -0
- data/lib/karafka/pro/routing/features/scheduled_messages/builder.rb +123 -0
- data/lib/karafka/pro/routing/features/scheduled_messages/config.rb +20 -0
- data/lib/karafka/pro/routing/features/scheduled_messages/contracts/topic.rb +32 -0
- data/lib/karafka/pro/routing/features/scheduled_messages/proxy.rb +19 -0
- data/lib/karafka/pro/routing/features/scheduled_messages/topic.rb +36 -0
- data/lib/karafka/pro/routing/features/scheduled_messages.rb +16 -0
- data/lib/karafka/pro/routing/features/swarm/config.rb +2 -10
- data/lib/karafka/pro/routing/features/swarm/contracts/routing.rb +2 -10
- data/lib/karafka/pro/routing/features/swarm/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/swarm/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/swarm.rb +2 -10
- data/lib/karafka/pro/routing/features/throttling/config.rb +2 -10
- data/lib/karafka/pro/routing/features/throttling/contracts/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/throttling/topic.rb +2 -10
- data/lib/karafka/pro/routing/features/throttling.rb +2 -10
- data/lib/karafka/pro/routing/features/virtual_partitions/config.rb +3 -10
- data/lib/karafka/pro/routing/features/virtual_partitions/contracts/topic.rb +3 -10
- data/lib/karafka/pro/routing/features/virtual_partitions/topic.rb +10 -12
- data/lib/karafka/pro/routing/features/virtual_partitions.rb +2 -10
- data/lib/karafka/pro/scheduled_messages/consumer.rb +177 -0
- data/lib/karafka/pro/scheduled_messages/contracts/config.rb +48 -0
- data/lib/karafka/pro/scheduled_messages/contracts/message.rb +88 -0
- data/lib/karafka/pro/scheduled_messages/daily_buffer.rb +71 -0
- data/lib/karafka/pro/scheduled_messages/day.rb +37 -0
- data/lib/karafka/pro/scheduled_messages/deserializers/headers.rb +38 -0
- data/lib/karafka/pro/scheduled_messages/deserializers/payload.rb +27 -0
- data/lib/karafka/pro/scheduled_messages/dispatcher.rb +114 -0
- data/lib/karafka/pro/scheduled_messages/errors.rb +20 -0
- data/lib/karafka/pro/scheduled_messages/max_epoch.rb +33 -0
- data/lib/karafka/pro/scheduled_messages/proxy.rb +177 -0
- data/lib/karafka/pro/scheduled_messages/schema_validator.rb +29 -0
- data/lib/karafka/pro/scheduled_messages/serializer.rb +47 -0
- data/lib/karafka/pro/scheduled_messages/setup/config.rb +52 -0
- data/lib/karafka/pro/scheduled_messages/state.rb +54 -0
- data/lib/karafka/pro/scheduled_messages/tracker.rb +56 -0
- data/lib/karafka/pro/scheduled_messages.rb +59 -0
- data/lib/karafka/pro/swarm/liveness_listener.rb +2 -10
- data/lib/karafka/processing/coordinator.rb +14 -0
- data/lib/karafka/processing/executor.rb +29 -1
- data/lib/karafka/processing/jobs/base.rb +13 -0
- data/lib/karafka/processing/jobs/consume.rb +2 -0
- data/lib/karafka/processing/jobs/eofed.rb +29 -0
- data/lib/karafka/processing/jobs/idle.rb +2 -0
- data/lib/karafka/processing/jobs/revoked.rb +2 -0
- data/lib/karafka/processing/jobs/shutdown.rb +2 -0
- data/lib/karafka/processing/jobs_builder.rb +6 -0
- data/lib/karafka/processing/schedulers/default.rb +1 -0
- data/lib/karafka/processing/strategies/aj_dlq_mom.rb +1 -1
- data/lib/karafka/processing/strategies/default.rb +45 -13
- data/lib/karafka/processing/strategies/dlq.rb +19 -5
- data/lib/karafka/processing/strategies/dlq_mom.rb +27 -8
- data/lib/karafka/processing/worker.rb +26 -13
- data/lib/karafka/railtie.rb +11 -42
- data/lib/karafka/routing/builder.rb +19 -1
- data/lib/karafka/routing/consumer_group.rb +9 -14
- data/lib/karafka/routing/features/dead_letter_queue/config.rb +3 -0
- data/lib/karafka/routing/features/dead_letter_queue/contracts/topic.rb +1 -0
- data/lib/karafka/routing/features/dead_letter_queue/topic.rb +7 -2
- data/lib/karafka/routing/features/eofed/config.rb +15 -0
- data/lib/karafka/routing/features/eofed/contracts/topic.rb +39 -0
- data/lib/karafka/routing/features/eofed/topic.rb +31 -0
- data/lib/karafka/routing/features/eofed.rb +14 -0
- data/lib/karafka/routing/subscription_group.rb +29 -1
- data/lib/karafka/routing/topic.rb +24 -1
- data/lib/karafka/runner.rb +10 -9
- data/lib/karafka/server.rb +37 -1
- data/lib/karafka/setup/attributes_map.rb +11 -4
- data/lib/karafka/setup/config.rb +11 -52
- data/lib/karafka/setup/defaults_injector.rb +64 -0
- data/lib/karafka/swarm/node.rb +2 -0
- data/lib/karafka/swarm/supervisor.rb +11 -2
- data/lib/karafka/templates/karafka.rb.erb +2 -2
- data/lib/karafka/version.rb +1 -1
- data/lib/karafka.rb +47 -7
- data.tar.gz.sig +0 -0
- metadata +116 -33
- metadata.gz.sig +0 -0
- data/certs/cert_chain.pem +0 -26
data/lib/karafka/cli/base.rb
CHANGED
|
@@ -41,22 +41,38 @@ module Karafka
|
|
|
41
41
|
class << self
|
|
42
42
|
# Loads proper environment with what is needed to run the CLI
|
|
43
43
|
def load
|
|
44
|
+
rails_env_rb = File.join(Dir.pwd, 'config/environment.rb')
|
|
45
|
+
is_rails = Kernel.const_defined?(:Rails) && File.exist?(rails_env_rb)
|
|
46
|
+
|
|
47
|
+
# If the boot file is disabled and this is a Rails app, we assume that user moved the
|
|
48
|
+
# karafka app configuration to initializers or other Rails loading related place.
|
|
49
|
+
# It is not recommended but some users tend to do this. In such cases we just try to load
|
|
50
|
+
# the Rails stuff hoping that it will also load Karafka stuff
|
|
51
|
+
if Karafka.boot_file.to_s == 'false' && is_rails
|
|
52
|
+
require rails_env_rb
|
|
53
|
+
|
|
54
|
+
return
|
|
55
|
+
end
|
|
56
|
+
|
|
44
57
|
# If there is a boot file, we need to require it as we expect it to contain
|
|
45
58
|
# Karafka app setup, routes, etc
|
|
46
59
|
if File.exist?(::Karafka.boot_file)
|
|
47
|
-
rails_env_rb = File.join(Dir.pwd, 'config/environment.rb')
|
|
48
|
-
|
|
49
60
|
# Load Rails environment file that starts Rails, so we can reference consumers and
|
|
50
61
|
# other things from `karafka.rb` file. This will work only for Rails, for non-rails
|
|
51
62
|
# a manual setup is needed
|
|
52
|
-
require rails_env_rb if
|
|
53
|
-
|
|
63
|
+
require rails_env_rb if is_rails
|
|
54
64
|
require Karafka.boot_file.to_s
|
|
65
|
+
|
|
66
|
+
return
|
|
67
|
+
end
|
|
68
|
+
|
|
55
69
|
# However when it is unavailable, we still want to be able to run help command
|
|
56
70
|
# and install command as they don't require configured app itself to run
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
71
|
+
return if %w[-h install].any? { |cmd| cmd == ARGV[0] }
|
|
72
|
+
|
|
73
|
+
# All other commands except help and install do require an existing boot file if it was
|
|
74
|
+
# declared
|
|
75
|
+
raise ::Karafka::Errors::MissingBootFileError, ::Karafka.boot_file
|
|
60
76
|
end
|
|
61
77
|
|
|
62
78
|
# Allows to set options for Thor cli
|
|
@@ -96,7 +112,7 @@ module Karafka
|
|
|
96
112
|
*[names, option[2], option[1]].flatten
|
|
97
113
|
) { |value| options[option[0]] = value }
|
|
98
114
|
end
|
|
99
|
-
end.parse
|
|
115
|
+
end.parse(ARGV)
|
|
100
116
|
|
|
101
117
|
options
|
|
102
118
|
end
|
data/lib/karafka/cli/install.rb
CHANGED
|
@@ -21,7 +21,7 @@ module Karafka
|
|
|
21
21
|
|
|
22
22
|
# Where should we map proper files from templates
|
|
23
23
|
INSTALL_FILES_MAP = {
|
|
24
|
-
'karafka.rb.erb' => Karafka.boot_file
|
|
24
|
+
'karafka.rb.erb' => Karafka.boot_file,
|
|
25
25
|
'application_consumer.rb.erb' => 'app/consumers/application_consumer.rb',
|
|
26
26
|
'example_consumer.rb.erb' => 'app/consumers/example_consumer.rb'
|
|
27
27
|
}.freeze
|
|
@@ -51,6 +51,7 @@ module Karafka
|
|
|
51
51
|
|
|
52
52
|
INSTALL_FILES_MAP.each do |source, target|
|
|
53
53
|
pathed_target = Karafka.root.join(target)
|
|
54
|
+
FileUtils.mkdir_p File.dirname(pathed_target)
|
|
54
55
|
|
|
55
56
|
template = File.read(Karafka.core_root.join("templates/#{source}"))
|
|
56
57
|
render = ::ERB.new(template, trim_mode: '-').result(binding)
|
data/lib/karafka/cli/server.rb
CHANGED
data/lib/karafka/cli/swarm.rb
CHANGED
|
@@ -89,9 +89,19 @@ module Karafka
|
|
|
89
89
|
desired_configs.transform_keys!(&:to_s)
|
|
90
90
|
|
|
91
91
|
topic_with_configs.configs.each do |config|
|
|
92
|
-
|
|
92
|
+
names = config.synonyms.map(&:name) << config.name
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
# We move forward only if given topic config is for altering
|
|
95
|
+
next if (desired_configs.keys & names).empty?
|
|
96
|
+
|
|
97
|
+
desired_config = nil
|
|
98
|
+
|
|
99
|
+
# We then find last defined value in our configs for a given attribute
|
|
100
|
+
# Since attributes can have synonyms, we select last one, which will represent the
|
|
101
|
+
# last defined value in case someone defined same multiple times
|
|
102
|
+
desired_configs.each do |name, value|
|
|
103
|
+
desired_config = value if names.include?(name)
|
|
104
|
+
end
|
|
95
105
|
|
|
96
106
|
# Do not migrate if existing and desired values are the same
|
|
97
107
|
next if desired_config == config.value
|
|
@@ -16,7 +16,10 @@ module Karafka
|
|
|
16
16
|
return false
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
changes = false
|
|
20
|
+
|
|
19
21
|
unless topics_to_create.empty?
|
|
22
|
+
changes = true
|
|
20
23
|
puts 'Following topics will be created:'
|
|
21
24
|
puts
|
|
22
25
|
|
|
@@ -33,20 +36,54 @@ module Karafka
|
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
unless topics_to_repartition.empty?
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
upscale = {}
|
|
40
|
+
downscale = {}
|
|
38
41
|
|
|
39
42
|
topics_to_repartition.each do |topic, partitions|
|
|
40
43
|
from = partitions
|
|
41
44
|
to = topic.declaratives.partitions
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
if from < to
|
|
47
|
+
upscale[topic] = partitions
|
|
48
|
+
else
|
|
49
|
+
downscale[topic] = partitions
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
unless upscale.empty?
|
|
54
|
+
changes = true
|
|
55
|
+
puts 'Following topics will be repartitioned:'
|
|
56
|
+
puts
|
|
57
|
+
|
|
58
|
+
upscale.each do |topic, partitions|
|
|
59
|
+
from = partitions
|
|
60
|
+
to = topic.declaratives.partitions
|
|
61
|
+
y = yellow('~')
|
|
62
|
+
puts " #{y} #{topic.name}:"
|
|
63
|
+
puts " #{y} partitions: \"#{red(from)}\" #{grey('=>')} \"#{green(to)}\""
|
|
64
|
+
puts
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
unless downscale.empty?
|
|
69
|
+
puts(
|
|
70
|
+
'Following topics repartitioning will be ignored as downscaling is not supported:'
|
|
71
|
+
)
|
|
45
72
|
puts
|
|
73
|
+
|
|
74
|
+
downscale.each do |topic, partitions|
|
|
75
|
+
from = partitions
|
|
76
|
+
to = topic.declaratives.partitions
|
|
77
|
+
|
|
78
|
+
puts " #{grey('~')} #{topic.name}:"
|
|
79
|
+
puts " #{grey('~')} partitions: \"#{grey(from)}\" #{grey('=>')} \"#{grey(to)}\""
|
|
80
|
+
puts
|
|
81
|
+
end
|
|
46
82
|
end
|
|
47
83
|
end
|
|
48
84
|
|
|
49
85
|
unless topics_to_alter.empty?
|
|
86
|
+
changes = true
|
|
50
87
|
puts 'Following topics will have configuration changes:'
|
|
51
88
|
puts
|
|
52
89
|
|
|
@@ -65,7 +102,7 @@ module Karafka
|
|
|
65
102
|
end
|
|
66
103
|
end
|
|
67
104
|
|
|
68
|
-
|
|
105
|
+
changes
|
|
69
106
|
end
|
|
70
107
|
|
|
71
108
|
private
|
|
@@ -143,14 +180,25 @@ module Karafka
|
|
|
143
180
|
}
|
|
144
181
|
|
|
145
182
|
scoped = @topics_to_alter[declarative][declarative_name]
|
|
183
|
+
# declarative name can be a synonym. In such cases we remap it during the discovery
|
|
184
|
+
# below
|
|
185
|
+
final_name = declarative_name
|
|
146
186
|
|
|
147
187
|
topic_c.configs.each do |config|
|
|
148
|
-
|
|
188
|
+
names = config.synonyms.map(&:name) << config.name
|
|
149
189
|
|
|
190
|
+
next unless names.include?(declarative_name)
|
|
191
|
+
|
|
192
|
+
# Always use a non-synonym name if differs
|
|
193
|
+
final_name = config.name
|
|
150
194
|
scoped[:action] = :change
|
|
151
195
|
scoped[:from] = config.value
|
|
152
196
|
end
|
|
153
197
|
|
|
198
|
+
# Aligns the name in case synonym was used
|
|
199
|
+
target = @topics_to_alter[declarative].delete(declarative_name)
|
|
200
|
+
@topics_to_alter[declarative][final_name] = target
|
|
201
|
+
|
|
154
202
|
# Remove change definitions that would migrate to the same value as present
|
|
155
203
|
@topics_to_alter[declarative].delete_if do |_name, details|
|
|
156
204
|
details[:from] == details[:to]
|
data/lib/karafka/cli/topics.rb
CHANGED
|
@@ -10,26 +10,53 @@ module Karafka
|
|
|
10
10
|
)
|
|
11
11
|
|
|
12
12
|
desc 'Allows for the topics management'
|
|
13
|
+
|
|
14
|
+
option(
|
|
15
|
+
:detailed_exitcode,
|
|
16
|
+
'Exists with 0 when no changes, 1 when error and 2 when changes present or applied',
|
|
17
|
+
TrueClass,
|
|
18
|
+
%w[
|
|
19
|
+
--detailed_exitcode
|
|
20
|
+
]
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
# We exit with 0 if no changes happened
|
|
24
|
+
NO_CHANGES_EXIT_CODE = 0
|
|
25
|
+
|
|
26
|
+
# When any changes happened (or could happen) we return 2 because 1 is default when Ruby
|
|
27
|
+
# crashes
|
|
28
|
+
CHANGES_EXIT_CODE = 2
|
|
29
|
+
|
|
30
|
+
private_constant :NO_CHANGES_EXIT_CODE, :CHANGES_EXIT_CODE
|
|
31
|
+
|
|
13
32
|
# @param action [String] action we want to take
|
|
14
33
|
def call(action = 'missing')
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
detailed_exit_code = options.fetch(:detailed_exitcode, false)
|
|
35
|
+
|
|
36
|
+
command = case action
|
|
37
|
+
when 'create'
|
|
38
|
+
Topics::Create
|
|
39
|
+
when 'delete'
|
|
40
|
+
Topics::Delete
|
|
41
|
+
when 'reset'
|
|
42
|
+
Topics::Reset
|
|
43
|
+
when 'repartition'
|
|
44
|
+
Topics::Repartition
|
|
45
|
+
when 'migrate'
|
|
46
|
+
Topics::Migrate
|
|
47
|
+
when 'align'
|
|
48
|
+
Topics::Align
|
|
49
|
+
when 'plan'
|
|
50
|
+
Topics::Plan
|
|
51
|
+
else
|
|
52
|
+
raise ::ArgumentError, "Invalid topics action: #{action}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
changes = command.new.call
|
|
56
|
+
|
|
57
|
+
return unless detailed_exit_code
|
|
58
|
+
|
|
59
|
+
changes ? exit(CHANGES_EXIT_CODE) : exit(NO_CHANGES_EXIT_CODE)
|
|
33
60
|
end
|
|
34
61
|
end
|
|
35
62
|
end
|
|
@@ -8,6 +8,8 @@ module Karafka
|
|
|
8
8
|
# It is threadsafe and provides some security measures so we won't end up operating on a
|
|
9
9
|
# closed consumer instance as it causes Ruby VM process to crash.
|
|
10
10
|
class Client
|
|
11
|
+
include ::Karafka::Core::Helpers::Time
|
|
12
|
+
|
|
11
13
|
attr_reader :rebalance_manager
|
|
12
14
|
|
|
13
15
|
# @return [Karafka::Routing::SubscriptionGroup] subscription group to which this client
|
|
@@ -24,7 +26,29 @@ module Karafka
|
|
|
24
26
|
# How many times should we retry polling in case of a failure
|
|
25
27
|
MAX_POLL_RETRIES = 20
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
# How much time of the total shutdown time can we wait for our manual unsubscribe before
|
|
30
|
+
# attempting to close without unsubscribe. We try to wait for 50% of the shutdown time
|
|
31
|
+
# before we move to a regular unsubscribe.
|
|
32
|
+
COOP_UNSUBSCRIBE_FACTOR = 0.5
|
|
33
|
+
|
|
34
|
+
# Errors upon which we early report that something is off without retrying prior to the
|
|
35
|
+
# report
|
|
36
|
+
EARLY_REPORT_ERRORS = [
|
|
37
|
+
:inconsistent_group_protocol, # 23
|
|
38
|
+
:max_poll_exceeded, # -147
|
|
39
|
+
:network_exception, # 13
|
|
40
|
+
:transport, # -195
|
|
41
|
+
:topic_authorization_failed, # 29
|
|
42
|
+
:group_authorization_failed, # 30
|
|
43
|
+
:cluster_authorization_failed, # 31
|
|
44
|
+
:illegal_generation,
|
|
45
|
+
# this will not recover as fencing is permanent
|
|
46
|
+
:fenced, # -144
|
|
47
|
+
# This can happen for many reasons, including issues with static membership being fenced
|
|
48
|
+
:fatal # -150
|
|
49
|
+
].freeze
|
|
50
|
+
|
|
51
|
+
private_constant :MAX_POLL_RETRIES, :COOP_UNSUBSCRIBE_FACTOR, :EARLY_REPORT_ERRORS
|
|
28
52
|
|
|
29
53
|
# Creates a new consumer instance.
|
|
30
54
|
#
|
|
@@ -42,7 +66,7 @@ module Karafka
|
|
|
42
66
|
@subscription_group = subscription_group
|
|
43
67
|
@buffer = RawMessagesBuffer.new
|
|
44
68
|
@tick_interval = ::Karafka::App.config.internal.tick_interval
|
|
45
|
-
@rebalance_manager = RebalanceManager.new(@subscription_group.id)
|
|
69
|
+
@rebalance_manager = RebalanceManager.new(@subscription_group.id, @buffer)
|
|
46
70
|
@rebalance_callback = Instrumentation::Callbacks::Rebalance.new(@subscription_group)
|
|
47
71
|
|
|
48
72
|
@interval_runner = Helpers::IntervalRunner.new do
|
|
@@ -91,8 +115,21 @@ module Karafka
|
|
|
91
115
|
# Fetch message within our time boundaries
|
|
92
116
|
response = poll(time_poll.remaining)
|
|
93
117
|
|
|
94
|
-
#
|
|
95
|
-
|
|
118
|
+
# We track when last polling happened so we can provide means to detect upcoming
|
|
119
|
+
# `max.poll.interval.ms` limit
|
|
120
|
+
@buffer.polled
|
|
121
|
+
|
|
122
|
+
case response
|
|
123
|
+
when :tick_time
|
|
124
|
+
nil
|
|
125
|
+
# We get a hash only in case of eof error
|
|
126
|
+
when Hash
|
|
127
|
+
@buffer.eof(response[:topic], response[:partition])
|
|
128
|
+
when nil
|
|
129
|
+
nil
|
|
130
|
+
else
|
|
131
|
+
@buffer << response
|
|
132
|
+
end
|
|
96
133
|
|
|
97
134
|
# Upon polling rebalance manager might have been updated.
|
|
98
135
|
# If partition revocation happens, we need to remove messages from revoked partitions
|
|
@@ -104,7 +141,7 @@ module Karafka
|
|
|
104
141
|
# Since rebalances do not occur often, we can run events polling as well without
|
|
105
142
|
# any throttling
|
|
106
143
|
events_poll
|
|
107
|
-
|
|
144
|
+
|
|
108
145
|
break
|
|
109
146
|
end
|
|
110
147
|
|
|
@@ -115,10 +152,11 @@ module Karafka
|
|
|
115
152
|
time_poll.checkpoint
|
|
116
153
|
|
|
117
154
|
# Finally once we've (potentially) removed revoked, etc, if no messages were returned
|
|
118
|
-
# and it was not an early poll exist, we can break.
|
|
155
|
+
# and it was not an early poll exist, we can break. We also break if we got the eof
|
|
156
|
+
# signaling to propagate it asap
|
|
119
157
|
# Worth keeping in mind, that the rebalance manager might have been updated despite no
|
|
120
158
|
# messages being returned during a poll
|
|
121
|
-
break
|
|
159
|
+
break if response.nil? || response.is_a?(Hash)
|
|
122
160
|
end
|
|
123
161
|
|
|
124
162
|
@buffer
|
|
@@ -257,14 +295,36 @@ module Karafka
|
|
|
257
295
|
|
|
258
296
|
# Gracefully stops topic consumption.
|
|
259
297
|
def stop
|
|
260
|
-
#
|
|
261
|
-
#
|
|
262
|
-
#
|
|
298
|
+
# librdkafka has several constant issues when shutting down during rebalance. This is
|
|
299
|
+
# an issue that gets back every few versions of librdkafka in a limited scope, for example
|
|
300
|
+
# for cooperative-sticky or in a general scope. This is why we unsubscribe and wait until
|
|
301
|
+
# we no longer have any assignments. That way librdkafka consumer shutdown should never
|
|
302
|
+
# happen with rebalance associated with the given consumer instance. Since we do not want
|
|
303
|
+
# to wait forever, we also impose a limit on how long should we wait. This prioritizes
|
|
304
|
+
# shutdown stability over endless wait.
|
|
305
|
+
#
|
|
306
|
+
# The `@unsubscribing` ensures that when there would be a direct close attempt, it
|
|
307
|
+
# won't get into this loop again. This can happen when supervision decides it should close
|
|
308
|
+
# things faster
|
|
309
|
+
#
|
|
310
|
+
# @see https://github.com/confluentinc/librdkafka/issues/4792
|
|
263
311
|
# @see https://github.com/confluentinc/librdkafka/issues/4527
|
|
264
|
-
if
|
|
312
|
+
if unsubscribe?
|
|
313
|
+
@unsubscribing = true
|
|
314
|
+
|
|
315
|
+
# Give 50% of time for the final close before we reach the forceful
|
|
316
|
+
max_wait = ::Karafka::App.config.shutdown_timeout * COOP_UNSUBSCRIBE_FACTOR
|
|
317
|
+
used = 0
|
|
318
|
+
stopped_at = monotonic_now
|
|
319
|
+
|
|
265
320
|
unsubscribe
|
|
266
321
|
|
|
267
322
|
until assignment.empty?
|
|
323
|
+
used += monotonic_now - stopped_at
|
|
324
|
+
stopped_at = monotonic_now
|
|
325
|
+
|
|
326
|
+
break if used >= max_wait
|
|
327
|
+
|
|
268
328
|
sleep(0.1)
|
|
269
329
|
|
|
270
330
|
ping
|
|
@@ -402,7 +462,9 @@ module Karafka
|
|
|
402
462
|
# then seek to the appropriate message
|
|
403
463
|
# We set the timeout to 2_000 to make sure that remote clusters handle this well
|
|
404
464
|
real_offsets = @wrapped_kafka.offsets_for_times(tpl)
|
|
405
|
-
|
|
465
|
+
# We always ask for one partition, so result will contain array with only one element
|
|
466
|
+
# that is the partition we were interested it regardless its number
|
|
467
|
+
detected_partition = real_offsets.to_h.dig(message.topic, 0)
|
|
406
468
|
|
|
407
469
|
# There always needs to be an offset. In case we seek into the future, where there
|
|
408
470
|
# are no offsets yet, we get -1 which indicates the most recent offset
|
|
@@ -545,11 +607,7 @@ module Karafka
|
|
|
545
607
|
# We want to report early on max poll interval exceeding because it may mean that the
|
|
546
608
|
# underlying processing is taking too much time and it is not LRJ
|
|
547
609
|
case e.code
|
|
548
|
-
when
|
|
549
|
-
early_report = true
|
|
550
|
-
when :network_exception # 13
|
|
551
|
-
early_report = true
|
|
552
|
-
when :transport # -195
|
|
610
|
+
when *EARLY_REPORT_ERRORS
|
|
553
611
|
early_report = true
|
|
554
612
|
# @see
|
|
555
613
|
# https://github.com/confluentinc/confluent-kafka-dotnet/issues/1366#issuecomment-821842990
|
|
@@ -563,11 +621,12 @@ module Karafka
|
|
|
563
621
|
# No sense in retrying when no topic/partition and we're no longer running
|
|
564
622
|
retryable = false unless Karafka::App.running?
|
|
565
623
|
# If we detect the end of partition which can happen if `enable.partition.eof` is set to
|
|
566
|
-
# true, we can just return
|
|
624
|
+
# true, we can just return fast. This will fast yield whatever set of messages we
|
|
567
625
|
# already have instead of waiting. This can be used for better latency control when we do
|
|
568
626
|
# not expect a lof of lag and want to quickly move to processing.
|
|
627
|
+
# We can also pass the eof notion to the consumers for improved decision making.
|
|
569
628
|
when :partition_eof
|
|
570
|
-
return
|
|
629
|
+
return e.details
|
|
571
630
|
end
|
|
572
631
|
|
|
573
632
|
if early_report || !retryable
|
|
@@ -647,24 +706,15 @@ module Karafka
|
|
|
647
706
|
subscriptions = @subscription_group.subscriptions
|
|
648
707
|
assignments = @subscription_group.assignments(consumer)
|
|
649
708
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
# We may have a case where in the middle of data polling, we've lost a partition.
|
|
657
|
-
# In a case like this we should remove all the pre-buffered messages from list partitions as
|
|
658
|
-
# we are no longer responsible in a given process for processing those messages and they
|
|
659
|
-
# should have been picked up by a different process.
|
|
660
|
-
def remove_revoked_and_duplicated_messages
|
|
661
|
-
@rebalance_manager.lost_partitions.each do |topic, partitions|
|
|
662
|
-
partitions.each do |partition|
|
|
663
|
-
@buffer.delete(topic, partition)
|
|
664
|
-
end
|
|
709
|
+
if subscriptions
|
|
710
|
+
consumer.subscribe(*subscriptions)
|
|
711
|
+
@mode = :subscribe
|
|
712
|
+
elsif assignments
|
|
713
|
+
consumer.assign(assignments)
|
|
714
|
+
@mode = :assign
|
|
665
715
|
end
|
|
666
716
|
|
|
667
|
-
|
|
717
|
+
consumer
|
|
668
718
|
end
|
|
669
719
|
|
|
670
720
|
# @return [Rdkafka::Consumer] librdkafka consumer instance
|
|
@@ -679,6 +729,23 @@ module Karafka
|
|
|
679
729
|
@kafka.start
|
|
680
730
|
@kafka
|
|
681
731
|
end
|
|
732
|
+
|
|
733
|
+
# Decides whether or not we should unsubscribe prior to closing.
|
|
734
|
+
#
|
|
735
|
+
# We cannot do it when there is a static group membership assignment as it would be
|
|
736
|
+
# reassigned.
|
|
737
|
+
# We cannot do it also for assign mode because then there are no subscriptions
|
|
738
|
+
# We also do not do it if there are no assignments at all as it does not make sense
|
|
739
|
+
#
|
|
740
|
+
# @return [Boolean] should we unsubscribe prior to shutdown
|
|
741
|
+
def unsubscribe?
|
|
742
|
+
return false if @unsubscribing
|
|
743
|
+
return false if @subscription_group.kafka.key?(:'group.instance.id')
|
|
744
|
+
return false if @mode != :subscribe
|
|
745
|
+
return false if assignment.empty?
|
|
746
|
+
|
|
747
|
+
true
|
|
748
|
+
end
|
|
682
749
|
end
|
|
683
750
|
end
|
|
684
751
|
end
|
|
@@ -253,7 +253,9 @@ module Karafka
|
|
|
253
253
|
|
|
254
254
|
reset
|
|
255
255
|
|
|
256
|
-
sleep
|
|
256
|
+
# Ruby sleep is in seconds
|
|
257
|
+
sleep_time = ::Karafka::App.config.internal.connection.reset_backoff / 10_000.0
|
|
258
|
+
sleep(sleep_time) && retry
|
|
257
259
|
end
|
|
258
260
|
|
|
259
261
|
# Resumes processing of partitions that were paused due to an error.
|
|
@@ -330,28 +332,58 @@ module Karafka
|
|
|
330
332
|
# given scheduler. It also handles the idle jobs when filtering API removed all messages
|
|
331
333
|
# and we need to run house-keeping
|
|
332
334
|
def build_and_schedule_flow_jobs
|
|
333
|
-
return if @messages_buffer.empty?
|
|
334
|
-
|
|
335
335
|
consume_jobs = []
|
|
336
336
|
idle_jobs = []
|
|
337
|
+
eofed_jobs = []
|
|
338
|
+
|
|
339
|
+
@messages_buffer.each do |topic, partition, messages, eof, last_polled_at|
|
|
340
|
+
# In case we did not receive any new messages without eof we skip.
|
|
341
|
+
# We may yield empty array here in case we have reached eof without new messages but in
|
|
342
|
+
# such cases, we can run an eof job
|
|
343
|
+
next if messages.empty? && !eof
|
|
337
344
|
|
|
338
|
-
@messages_buffer.each do |topic, partition, messages|
|
|
339
345
|
coordinator = @coordinators.find_or_create(topic, partition)
|
|
340
|
-
|
|
346
|
+
coordinator.eofed = eof
|
|
347
|
+
coordinator.last_polled_at = last_polled_at
|
|
348
|
+
|
|
349
|
+
# If we did not receive any messages and we did receive eof signal, we run the eofed
|
|
350
|
+
# jobs so user can take actions on reaching eof
|
|
351
|
+
if messages.empty? && eof
|
|
352
|
+
# If user wants to run the eofed jobs on eof we do it. Otherwise we just allow it to
|
|
353
|
+
# pass through. This allows to configure if user actually wants to have `#eofed`
|
|
354
|
+
# logic or if he wants to only use fast eof work yield
|
|
355
|
+
if coordinator.topic.eofed?
|
|
356
|
+
@executors.find_all_or_create(topic, partition, coordinator).each do |executor|
|
|
357
|
+
coordinator.increment(:eofed)
|
|
358
|
+
eofed_jobs << @jobs_builder.eofed(executor)
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
next
|
|
363
|
+
end
|
|
364
|
+
|
|
341
365
|
coordinator.start(messages)
|
|
342
366
|
|
|
367
|
+
# If it is not an eof and there are no new messages, we just run house-keeping
|
|
368
|
+
#
|
|
343
369
|
# We do not increment coordinator for idle job because it's not a user related one
|
|
344
370
|
# and it will not go through a standard lifecycle. Same applies to revoked and shutdown
|
|
345
371
|
if messages.empty?
|
|
372
|
+
# Start work coordination for this topic partition
|
|
346
373
|
coordinator.increment(:idle)
|
|
347
374
|
executor = @executors.find_or_create(topic, partition, 0, coordinator)
|
|
348
375
|
idle_jobs << @jobs_builder.idle(executor)
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
376
|
+
|
|
377
|
+
next
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# If there are messages, it is irrelevant if eof or not as consumption needs to happen
|
|
381
|
+
#
|
|
382
|
+
# Start work coordination for this topic partition
|
|
383
|
+
@partitioner.call(topic, messages, coordinator) do |group_id, partition_messages|
|
|
384
|
+
coordinator.increment(:consume)
|
|
385
|
+
executor = @executors.find_or_create(topic, partition, group_id, coordinator)
|
|
386
|
+
consume_jobs << @jobs_builder.consume(executor, partition_messages)
|
|
355
387
|
end
|
|
356
388
|
end
|
|
357
389
|
|
|
@@ -367,6 +399,11 @@ module Karafka
|
|
|
367
399
|
consume_jobs.each(&:before_schedule)
|
|
368
400
|
@scheduler.on_schedule_consumption(consume_jobs)
|
|
369
401
|
end
|
|
402
|
+
|
|
403
|
+
unless eofed_jobs.empty?
|
|
404
|
+
eofed_jobs.each(&:before_schedule)
|
|
405
|
+
@scheduler.on_schedule_eofed(eofed_jobs)
|
|
406
|
+
end
|
|
370
407
|
end
|
|
371
408
|
|
|
372
409
|
# Builds and schedules periodic jobs for topics partitions for which no messages were
|
|
@@ -23,9 +23,13 @@ module Karafka
|
|
|
23
23
|
def initialize(subscription_group)
|
|
24
24
|
@subscription_group = subscription_group
|
|
25
25
|
@size = 0
|
|
26
|
+
|
|
26
27
|
@groups = Hash.new do |topic_groups, topic|
|
|
27
28
|
topic_groups[topic] = Hash.new do |partition_groups, partition|
|
|
28
|
-
partition_groups[partition] =
|
|
29
|
+
partition_groups[partition] = {
|
|
30
|
+
eof: false,
|
|
31
|
+
messages: []
|
|
32
|
+
}
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
end
|
|
@@ -33,24 +37,31 @@ module Karafka
|
|
|
33
37
|
# Remaps raw messages from the raw messages buffer to Karafka messages
|
|
34
38
|
# @param raw_messages_buffer [RawMessagesBuffer] buffer with raw messages
|
|
35
39
|
def remap(raw_messages_buffer)
|
|
36
|
-
clear
|
|
40
|
+
clear
|
|
37
41
|
|
|
38
42
|
# Since it happens "right after" we've received the messages, it is close enough it time
|
|
39
43
|
# to be used as the moment we received messages.
|
|
40
44
|
received_at = Time.now
|
|
45
|
+
last_polled_at = raw_messages_buffer.last_polled_at
|
|
41
46
|
|
|
42
|
-
raw_messages_buffer.each do |topic, partition, messages|
|
|
47
|
+
raw_messages_buffer.each do |topic, partition, messages, eof|
|
|
43
48
|
@size += messages.count
|
|
44
49
|
|
|
45
50
|
ktopic = @subscription_group.topics.find(topic)
|
|
46
51
|
|
|
47
|
-
|
|
52
|
+
built_messages = messages.map do |message|
|
|
48
53
|
Messages::Builders::Message.call(
|
|
49
54
|
message,
|
|
50
55
|
ktopic,
|
|
51
56
|
received_at
|
|
52
57
|
)
|
|
53
58
|
end
|
|
59
|
+
|
|
60
|
+
@groups[topic][partition] = {
|
|
61
|
+
eof: eof,
|
|
62
|
+
messages: built_messages,
|
|
63
|
+
last_polled_at: last_polled_at
|
|
64
|
+
}
|
|
54
65
|
end
|
|
55
66
|
end
|
|
56
67
|
|
|
@@ -59,10 +70,12 @@ module Karafka
|
|
|
59
70
|
# @yieldparam [String] topic name
|
|
60
71
|
# @yieldparam [Integer] partition number
|
|
61
72
|
# @yieldparam [Array<Karafka::Messages::Message>] messages from a given topic partition
|
|
73
|
+
# @yieldparam [Boolean] true if eof, false otherwise
|
|
74
|
+
# @yieldparam [Float] last polled at monotonic clock time
|
|
62
75
|
def each
|
|
63
76
|
@groups.each do |topic, partitions|
|
|
64
|
-
partitions.each do |partition,
|
|
65
|
-
yield(topic, partition, messages)
|
|
77
|
+
partitions.each do |partition, details|
|
|
78
|
+
yield(topic, partition, details[:messages], details[:eof], details[:last_polled_at])
|
|
66
79
|
end
|
|
67
80
|
end
|
|
68
81
|
end
|