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/config/locales/errors.yml
CHANGED
|
@@ -14,6 +14,7 @@ en:
|
|
|
14
14
|
pause_max_timeout_format: needs to be an integer bigger than 0
|
|
15
15
|
pause_with_exponential_backoff_format: needs to be either true or false
|
|
16
16
|
strict_topics_namespacing_format: needs to be either true or false
|
|
17
|
+
strict_declarative_topics_format: needs to be either true or false
|
|
17
18
|
shutdown_timeout_format: needs to be an integer bigger than 0
|
|
18
19
|
max_wait_time_format: needs to be an integer bigger than 0
|
|
19
20
|
max_wait_time_max_wait_time_vs_swarm_node_report_timeout: >
|
|
@@ -33,6 +34,8 @@ en:
|
|
|
33
34
|
internal.processing.partitioner_class_format: cannot be nil
|
|
34
35
|
internal.processing.strategy_selector_format: cannot be nil
|
|
35
36
|
internal.processing.expansions_selector_format: cannot be nil
|
|
37
|
+
internal.processing.executor_class_format: cannot be nil
|
|
38
|
+
internal.processing.worker_job_call_wrapper_format: 'needs to be false or respond to #wrap'
|
|
36
39
|
|
|
37
40
|
internal.active_job.dispatcher_format: cannot be nil
|
|
38
41
|
internal.active_job.job_options_contract_format: cannot be nil
|
|
@@ -49,6 +52,7 @@ en:
|
|
|
49
52
|
|
|
50
53
|
internal.connection.manager_format: needs to be present
|
|
51
54
|
internal.connection.conductor_format: needs to be present
|
|
55
|
+
internal.connection.reset_backoff_format: needs to be an integer bigger or equal to 1000
|
|
52
56
|
internal.connection.proxy.query_watermark_offsets.timeout_format: needs to be an integer bigger than 0
|
|
53
57
|
internal.connection.proxy.query_watermark_offsets.max_attempts_format: needs to be an integer bigger than 0
|
|
54
58
|
internal.connection.proxy.query_watermark_offsets.wait_time_format: needs to be an integer bigger than 0
|
|
@@ -91,6 +95,7 @@ en:
|
|
|
91
95
|
|
|
92
96
|
topic:
|
|
93
97
|
kafka: needs to be a hash with kafka scope settings details
|
|
98
|
+
kafka_format: needs to be a filled hash
|
|
94
99
|
missing: needs to be present
|
|
95
100
|
max_messages_format: 'needs to be an integer bigger than 0'
|
|
96
101
|
max_wait_time_format: 'needs to be an integer bigger than 0'
|
|
@@ -112,17 +117,22 @@ en:
|
|
|
112
117
|
dead_letter_queue.transactional_format: needs to be either true or false
|
|
113
118
|
dead_letter_queue.dispatch_method_format: 'needs to be either #produce_sync or #produce_async'
|
|
114
119
|
dead_letter_queue.marking_method_format: 'needs to be either #mark_as_consumed or #mark_as_consumed!'
|
|
120
|
+
dead_letter_queue.mark_after_dispatch_format: 'needs to be true, false or nil'
|
|
115
121
|
|
|
116
122
|
active_format: needs to be either true or false
|
|
117
123
|
|
|
124
|
+
eofed.active_format: needs to be either true or false
|
|
125
|
+
eofed.kafka_enable: 'cannot be enabled without enable.partition.eof set to true'
|
|
126
|
+
|
|
118
127
|
declaratives.partitions_format: needs to be more or equal to 1
|
|
119
128
|
declaratives.active_format: needs to be true
|
|
120
129
|
declaratives.replication_factor_format: needs to be more or equal to 1
|
|
121
130
|
declaratives.details_format: needs to be a hash with only symbol keys
|
|
122
131
|
|
|
123
132
|
inconsistent_namespacing: |
|
|
124
|
-
needs to
|
|
125
|
-
|
|
133
|
+
needs to follow a consistent namespacing style using either dots (.) or underscores (_), but not both.
|
|
134
|
+
This ensures proper Kafka metrics reporting and avoids name collisions.
|
|
135
|
+
To disable this validation, set config.strict_topics_namespacing to false.
|
|
126
136
|
|
|
127
137
|
deserializers.active_format: 'needs to be true'
|
|
128
138
|
deserializers.payload_format: 'needs to respond to #call'
|
|
@@ -132,18 +142,24 @@ en:
|
|
|
132
142
|
consumer_group:
|
|
133
143
|
missing: needs to be present
|
|
134
144
|
topics_names_not_unique: all topic names within a single consumer group must be unique
|
|
145
|
+
topics_many_consumers_same_topic: 'topic within a single consumer group cannot have distinct consumers'
|
|
135
146
|
id_format: 'needs to be a string with a Kafka accepted format'
|
|
136
147
|
topics_format: needs to be a non-empty array
|
|
137
148
|
topics_namespaced_names_not_unique: |
|
|
138
149
|
all topic names within a single consumer group must be unique considering namespacing styles
|
|
139
150
|
disable this validation by setting config.strict_topics_namespacing to false
|
|
140
151
|
|
|
152
|
+
routing:
|
|
153
|
+
without_declarative_definition: lacks explicit declarative topics definition
|
|
154
|
+
|
|
141
155
|
job_options:
|
|
142
156
|
missing: needs to be present
|
|
143
157
|
dispatch_method_format: needs to be either :produce_async or :produce_sync
|
|
144
158
|
dispatch_many_method_format: needs to be either :produce_many_async or :produce_many_sync
|
|
145
159
|
partitioner_format: 'needs to respond to #call'
|
|
146
160
|
partition_key_type_format: 'needs to be either :key or :partition_key'
|
|
161
|
+
producer_format: 'needs to respond to #call'
|
|
162
|
+
scheduled_messages_topic_format: 'needs to be a string with a Kafka accepted format'
|
|
147
163
|
|
|
148
164
|
test:
|
|
149
165
|
missing: needs to be present
|
|
@@ -4,6 +4,7 @@ en:
|
|
|
4
4
|
virtual_partitions.partitioner_respond_to_call: needs to be defined and needs to respond to `#call`
|
|
5
5
|
virtual_partitions.max_partitions_format: needs to be equal or more than 1
|
|
6
6
|
virtual_partitions.offset_metadata_strategy_format: needs to be either :exact or :current
|
|
7
|
+
virtual_partitions.reducer_format: "needs to respond to `#call`"
|
|
7
8
|
|
|
8
9
|
long_running_job.active_format: needs to be either true or false
|
|
9
10
|
|
|
@@ -62,6 +63,10 @@ en:
|
|
|
62
63
|
swarm.nodes_format: needs to be a range, array of nodes ids or a hash with direct assignments
|
|
63
64
|
swarm_nodes_with_non_existent_nodes: includes unreachable nodes ids
|
|
64
65
|
|
|
66
|
+
recurring_tasks.active_format: 'needs to be boolean'
|
|
67
|
+
scheduled_messages.active_format: 'needs to be boolean'
|
|
68
|
+
scheduled_messages.active_missing: 'needs to be boolean'
|
|
69
|
+
|
|
65
70
|
direct_assignments.active_missing: needs to be present
|
|
66
71
|
direct_assignments.active_format: 'needs to be boolean'
|
|
67
72
|
direct_assignments.partitions_missing: 'needs to be present'
|
|
@@ -71,6 +76,14 @@ en:
|
|
|
71
76
|
direct_assignments_swarm_overbooked: 'cannot allocate partitions in swarm that were not assigned'
|
|
72
77
|
direct_assignments_patterns_active: 'patterns cannot be used with direct assignments'
|
|
73
78
|
|
|
79
|
+
adaptive_iterator.active_missing: needs to be present
|
|
80
|
+
adaptive_iterator.active_format: 'needs to be boolean'
|
|
81
|
+
adaptive_iterator.marking_method_format: 'needs to be either #mark_as_consumed or #mark_as_consumed!'
|
|
82
|
+
adaptive_iterator.clean_after_yielding_format: 'needs to be boolean'
|
|
83
|
+
adaptive_iterator.safety_margin_format: 'needs to be between 1 and 99'
|
|
84
|
+
adaptive_iterator_with_virtual_partitions: 'cannot be used with virtual partitions'
|
|
85
|
+
adaptive_iterator_with_long_running_job: 'cannot be used with long running jobs'
|
|
86
|
+
|
|
74
87
|
consumer_group:
|
|
75
88
|
patterns_format: must be an array with hashes
|
|
76
89
|
patterns_missing: needs to be present
|
|
@@ -98,5 +111,36 @@ en:
|
|
|
98
111
|
patterns.ttl_format: needs to be an integer bigger than 0
|
|
99
112
|
patterns.ttl_missing: needs to be present
|
|
100
113
|
|
|
114
|
+
recurring_tasks.consumer_class_format: 'needs to inherit from Karafka::BaseConsumer'
|
|
115
|
+
recurring_tasks.group_id_format: 'needs to be a string with a Kafka accepted format'
|
|
116
|
+
recurring_tasks.topics.schedules_format: 'needs to be a string with a Kafka accepted format'
|
|
117
|
+
recurring_tasks.topics.logs_format: 'needs to be a string with a Kafka accepted format'
|
|
118
|
+
recurring_tasks.interval_format: 'needs to be equal or more than 1000 and an integer'
|
|
119
|
+
recurring_tasks.deserializer_format: 'needs to be configured'
|
|
120
|
+
recurring_tasks.logging_format: needs to be a boolean
|
|
121
|
+
|
|
122
|
+
scheduled_messages.consumer_class_format: 'must be a class'
|
|
123
|
+
scheduled_messages.dispatcher_class_format: 'must be a class'
|
|
124
|
+
scheduled_messages.flush_batch_size_format: needs to be an integer bigger than 0
|
|
125
|
+
scheduled_messages.interval_format: needs to be an integer bigger or equal to 1000
|
|
126
|
+
scheduled_messages.deserializers.headers_format: cannot be nil
|
|
127
|
+
scheduled_messages.deserializers.payload_format: cannot be nil
|
|
128
|
+
scheduled_messages.group_id_format: 'needs to be a string with a Kafka accepted format'
|
|
129
|
+
scheduled_messages.states_postfix_format: 'needs to be a string with a Kafka accepted format'
|
|
130
|
+
|
|
101
131
|
routing:
|
|
102
132
|
swarm_nodes_not_used: 'At least one of the nodes has no assignments'
|
|
133
|
+
|
|
134
|
+
recurring_tasks:
|
|
135
|
+
id_format: 'can include only alphanumeric characters (a-z, A-Z, 0-9), hyphens (-), and underscores (_)'
|
|
136
|
+
cron_format: must be a non-empty string
|
|
137
|
+
enabled_format: needs to be a boolean
|
|
138
|
+
changed_format: needs to be a boolean
|
|
139
|
+
previous_time_format: needs to be a numerical or time
|
|
140
|
+
|
|
141
|
+
scheduled_messages_message:
|
|
142
|
+
key_missing: must be present and should be unique within the partition
|
|
143
|
+
key_format: needs to be a non-empty string unique within the partition
|
|
144
|
+
headers_schedule_target_epoch_in_the_past: 'scheduling cannot happen in the past'
|
|
145
|
+
headers_format: are not correct
|
|
146
|
+
not_a_scheduled_messages_topic: 'the envelope topic is not a scheduled messages topic'
|
data/docker-compose.yml
CHANGED
data/karafka.gemspec
CHANGED
|
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
|
12
12
|
spec.authors = ['Maciej Mensfeld']
|
|
13
13
|
spec.email = %w[contact@karafka.io]
|
|
14
14
|
spec.homepage = 'https://karafka.io'
|
|
15
|
-
spec.licenses = %w[LGPL-3.0 Commercial]
|
|
15
|
+
spec.licenses = %w[LGPL-3.0-only Commercial]
|
|
16
16
|
spec.summary = 'Karafka is Ruby and Rails efficient Kafka processing framework.'
|
|
17
17
|
spec.description = <<-DESC
|
|
18
18
|
Karafka is Ruby and Rails efficient Kafka processing framework.
|
|
@@ -21,8 +21,10 @@ Gem::Specification.new do |spec|
|
|
|
21
21
|
without having to focus on things that are not your business domain.
|
|
22
22
|
DESC
|
|
23
23
|
|
|
24
|
-
spec.add_dependency '
|
|
25
|
-
spec.add_dependency '
|
|
24
|
+
spec.add_dependency 'base64', '~> 0.2'
|
|
25
|
+
spec.add_dependency 'karafka-core', '>= 2.4.4', '< 2.5.0'
|
|
26
|
+
spec.add_dependency 'karafka-rdkafka', '>= 0.17.2'
|
|
27
|
+
spec.add_dependency 'waterdrop', '>= 2.7.3', '< 3.0.0'
|
|
26
28
|
spec.add_dependency 'zeitwerk', '~> 2.3'
|
|
27
29
|
|
|
28
30
|
spec.required_ruby_version = '>= 3.0.0'
|
|
@@ -31,7 +33,7 @@ Gem::Specification.new do |spec|
|
|
|
31
33
|
spec.signing_key = File.expand_path('~/.ssh/gem-private_key.pem')
|
|
32
34
|
end
|
|
33
35
|
|
|
34
|
-
spec.cert_chain = %w[certs/
|
|
36
|
+
spec.cert_chain = %w[certs/cert.pem]
|
|
35
37
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
|
|
36
38
|
spec.executables = %w[karafka]
|
|
37
39
|
spec.require_paths = %w[lib]
|
|
@@ -7,27 +7,38 @@ module ActiveJob
|
|
|
7
7
|
# Karafka adapter for enqueuing jobs
|
|
8
8
|
# This is here for ease of integration with ActiveJob.
|
|
9
9
|
class KarafkaAdapter
|
|
10
|
+
include Karafka::Helpers::ConfigImporter.new(
|
|
11
|
+
dispatcher: %i[internal active_job dispatcher]
|
|
12
|
+
)
|
|
13
|
+
|
|
10
14
|
# Enqueues the job using the configured dispatcher
|
|
11
15
|
#
|
|
12
16
|
# @param job [Object] job that should be enqueued
|
|
13
17
|
def enqueue(job)
|
|
14
|
-
|
|
18
|
+
dispatcher.dispatch(job)
|
|
15
19
|
end
|
|
16
20
|
|
|
17
21
|
# Enqueues multiple jobs in one go
|
|
18
22
|
# @param jobs [Array<Object>] jobs that we want to enqueue
|
|
19
23
|
# @return [Integer] number of jobs enqueued (required by Rails)
|
|
20
24
|
def enqueue_all(jobs)
|
|
21
|
-
|
|
25
|
+
dispatcher.dispatch_many(jobs)
|
|
22
26
|
jobs.size
|
|
23
27
|
end
|
|
24
28
|
|
|
25
|
-
#
|
|
29
|
+
# Delegates time sensitive dispatch to the dispatcher. OSS will raise error, Pro will handle
|
|
30
|
+
# this as it supports scheduled messages.
|
|
26
31
|
#
|
|
27
|
-
# @param
|
|
28
|
-
# @param
|
|
29
|
-
def enqueue_at(
|
|
30
|
-
|
|
32
|
+
# @param job [Object] job we want to enqueue
|
|
33
|
+
# @param timestamp [Time] time when job should run
|
|
34
|
+
def enqueue_at(job, timestamp)
|
|
35
|
+
dispatcher.dispatch_at(job, timestamp)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [true] should we by default enqueue after the transaction and not during.
|
|
39
|
+
# Defaults to true to prevent weird issues during rollbacks, etc.
|
|
40
|
+
def enqueue_after_transaction_commit?
|
|
41
|
+
true
|
|
31
42
|
end
|
|
32
43
|
end
|
|
33
44
|
end
|
|
@@ -46,6 +46,19 @@ module Karafka
|
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
+
# Raises info, that Karafka backend does not support scheduling jobs
|
|
50
|
+
#
|
|
51
|
+
# @param _job [Object] job we cannot enqueue
|
|
52
|
+
# @param _timestamp [Time] time when job should run
|
|
53
|
+
#
|
|
54
|
+
# @note Karafka Pro supports this feature
|
|
55
|
+
def dispatch_at(_job, _timestamp)
|
|
56
|
+
raise NotImplementedError, <<~ERROR_MESSAGE
|
|
57
|
+
This queueing backend does not support scheduling jobs.
|
|
58
|
+
Consider using Karafka Pro, which supports this via the Scheduled Messages feature.
|
|
59
|
+
ERROR_MESSAGE
|
|
60
|
+
end
|
|
61
|
+
|
|
49
62
|
private
|
|
50
63
|
|
|
51
64
|
# @param job [ActiveJob::Base] job
|
|
@@ -23,6 +23,9 @@ module Karafka
|
|
|
23
23
|
# them
|
|
24
24
|
App.config.internal.active_job.job_options_contract.validate!(new_options)
|
|
25
25
|
|
|
26
|
+
# We need to modify this hash because otherwise we would modify parent hash.
|
|
27
|
+
self._karafka_options = _karafka_options.dup
|
|
28
|
+
|
|
26
29
|
new_options.each do |name, value|
|
|
27
30
|
_karafka_options[name] = value
|
|
28
31
|
end
|
data/lib/karafka/admin.rb
CHANGED
|
@@ -10,6 +10,12 @@ module Karafka
|
|
|
10
10
|
# Cluster on which operations are performed can be changed via `admin.kafka` config, however
|
|
11
11
|
# there is no multi-cluster runtime support.
|
|
12
12
|
module Admin
|
|
13
|
+
# More or less number of seconds of 1 hundred years
|
|
14
|
+
# Used for time referencing that does not have to be accurate but needs to be big
|
|
15
|
+
HUNDRED_YEARS = 100 * 365.25 * 24 * 60 * 60
|
|
16
|
+
|
|
17
|
+
private_constant :HUNDRED_YEARS
|
|
18
|
+
|
|
13
19
|
class << self
|
|
14
20
|
# Allows us to read messages from the topic
|
|
15
21
|
#
|
|
@@ -156,6 +162,18 @@ module Karafka
|
|
|
156
162
|
#
|
|
157
163
|
# @example Move offset to 5 seconds ago on partition 2
|
|
158
164
|
# Karafka::Admin.seek_consumer_group('group-id', { 'topic' => { 2 => 5.seconds.ago } })
|
|
165
|
+
#
|
|
166
|
+
# @example Move to the earliest offset on all the partitions of a topic
|
|
167
|
+
# Karafka::Admin.seek_consumer_group('group-id', { 'topic' => 'earliest' })
|
|
168
|
+
#
|
|
169
|
+
# @example Move to the latest (high-watermark) offset on all the partitions of a topic
|
|
170
|
+
# Karafka::Admin.seek_consumer_group('group-id', { 'topic' => 'latest' })
|
|
171
|
+
#
|
|
172
|
+
# @example Move offset of a single partition to earliest
|
|
173
|
+
# Karafka::Admin.seek_consumer_group('group-id', { 'topic' => { 1 => 'earliest' } })
|
|
174
|
+
#
|
|
175
|
+
# @example Move offset of a single partition to latest
|
|
176
|
+
# Karafka::Admin.seek_consumer_group('group-id', { 'topic' => { 1 => 'latest' } })
|
|
159
177
|
def seek_consumer_group(consumer_group_id, topics_with_partitions_and_offsets)
|
|
160
178
|
tpl_base = {}
|
|
161
179
|
|
|
@@ -174,6 +192,32 @@ module Karafka
|
|
|
174
192
|
end
|
|
175
193
|
end
|
|
176
194
|
|
|
195
|
+
tpl_base.each_value do |partitions|
|
|
196
|
+
partitions.transform_values! do |position|
|
|
197
|
+
# Support both symbol and string based references
|
|
198
|
+
casted_position = position.is_a?(Symbol) ? position.to_s : position
|
|
199
|
+
|
|
200
|
+
# This remap allows us to transform some special cases in a reference that can be
|
|
201
|
+
# understood by Kafka
|
|
202
|
+
case casted_position
|
|
203
|
+
# Earliest is not always 0. When compacting/deleting it can be much later, that's why
|
|
204
|
+
# we fetch the oldest possible offset
|
|
205
|
+
when 'earliest'
|
|
206
|
+
Time.now - HUNDRED_YEARS
|
|
207
|
+
# Latest will always be the high-watermark offset and we can get it just by getting
|
|
208
|
+
# a future position
|
|
209
|
+
when 'latest'
|
|
210
|
+
Time.now + HUNDRED_YEARS
|
|
211
|
+
# Same as `'latest'`
|
|
212
|
+
when false
|
|
213
|
+
Time.now - HUNDRED_YEARS
|
|
214
|
+
# Regular offset case
|
|
215
|
+
else
|
|
216
|
+
position
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
177
221
|
tpl = Rdkafka::Consumer::TopicPartitionList.new
|
|
178
222
|
# In case of time based location, we need to to a pre-resolution, that's why we keep it
|
|
179
223
|
# separately
|
|
@@ -230,6 +274,48 @@ module Karafka
|
|
|
230
274
|
end
|
|
231
275
|
end
|
|
232
276
|
|
|
277
|
+
# Takes consumer group and its topics and migrates all the offsets to a new named group
|
|
278
|
+
#
|
|
279
|
+
# @param previous_name [String] old consumer group name
|
|
280
|
+
# @param new_name [String] new consumer group name
|
|
281
|
+
# @param topics [Array<String>] topics for which we want to migrate offsets during rename
|
|
282
|
+
# @param delete_previous [Boolean] should we delete previous consumer group after rename.
|
|
283
|
+
# Defaults to true.
|
|
284
|
+
#
|
|
285
|
+
# @note This method should **not** be executed on a running consumer group as it creates a
|
|
286
|
+
# "fake" consumer and uses it to move offsets.
|
|
287
|
+
#
|
|
288
|
+
# @note After migration unless `delete_previous` is set to `false`, old group will be
|
|
289
|
+
# removed.
|
|
290
|
+
#
|
|
291
|
+
# @note If new consumer group exists, old offsets will be added to it.
|
|
292
|
+
def rename_consumer_group(previous_name, new_name, topics, delete_previous: true)
|
|
293
|
+
remap = Hash.new { |h, k| h[k] = {} }
|
|
294
|
+
|
|
295
|
+
old_lags = read_lags_with_offsets({ previous_name => topics })
|
|
296
|
+
|
|
297
|
+
return if old_lags.empty?
|
|
298
|
+
|
|
299
|
+
read_lags_with_offsets({ previous_name => topics })
|
|
300
|
+
.fetch(previous_name)
|
|
301
|
+
.each do |topic, partitions|
|
|
302
|
+
partitions.each do |partition_id, details|
|
|
303
|
+
offset = details[:offset]
|
|
304
|
+
|
|
305
|
+
# No offset on this partition
|
|
306
|
+
next if offset.negative?
|
|
307
|
+
|
|
308
|
+
remap[topic][partition_id] = offset
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
seek_consumer_group(new_name, remap)
|
|
313
|
+
|
|
314
|
+
return unless delete_previous
|
|
315
|
+
|
|
316
|
+
delete_consumer_group(previous_name)
|
|
317
|
+
end
|
|
318
|
+
|
|
233
319
|
# Removes given consumer group (if exists)
|
|
234
320
|
#
|
|
235
321
|
# @param consumer_group_id [String] consumer group name
|
data/lib/karafka/app.rb
CHANGED
|
@@ -95,6 +95,23 @@ module Karafka
|
|
|
95
95
|
end
|
|
96
96
|
RUBY
|
|
97
97
|
end
|
|
98
|
+
|
|
99
|
+
# Forces the debug setup onto Karafka and default WaterDrop producer.
|
|
100
|
+
# This needs to run prior to any operations that would cache state, like consuming or
|
|
101
|
+
# producing messages.
|
|
102
|
+
#
|
|
103
|
+
# @param contexts [String] librdkafka low level debug contexts for granular debugging
|
|
104
|
+
def debug!(contexts = 'all')
|
|
105
|
+
logger.level = ::Logger::DEBUG
|
|
106
|
+
producer.config.logger.level = ::Logger::DEBUG
|
|
107
|
+
|
|
108
|
+
config.kafka[:debug] = contexts
|
|
109
|
+
producer.config.kafka[:debug] = contexts
|
|
110
|
+
|
|
111
|
+
consumer_groups.map(&:topics).flat_map(&:to_a).each do |topic|
|
|
112
|
+
topic.kafka[:debug] = contexts
|
|
113
|
+
end
|
|
114
|
+
end
|
|
98
115
|
end
|
|
99
116
|
end
|
|
100
117
|
end
|
|
@@ -6,14 +6,19 @@ module Karafka
|
|
|
6
6
|
class BaseConsumer
|
|
7
7
|
# Allow for consumer instance tagging for instrumentation
|
|
8
8
|
include ::Karafka::Core::Taggable
|
|
9
|
+
include Helpers::ConfigImporter.new(
|
|
10
|
+
monitor: %i[monitor]
|
|
11
|
+
)
|
|
9
12
|
|
|
10
13
|
extend Forwardable
|
|
11
14
|
|
|
12
|
-
def_delegators :@coordinator, :topic, :partition
|
|
15
|
+
def_delegators :@coordinator, :topic, :partition, :eofed?, :seek_offset, :seek_offset=
|
|
13
16
|
|
|
14
17
|
def_delegators :producer, :produce_async, :produce_sync, :produce_many_async,
|
|
15
18
|
:produce_many_sync
|
|
16
19
|
|
|
20
|
+
def_delegators :messages, :each
|
|
21
|
+
|
|
17
22
|
# @return [String] id of the current consumer
|
|
18
23
|
attr_reader :id
|
|
19
24
|
# @return [Karafka::Routing::Topic] topic to which a given consumer is subscribed
|
|
@@ -31,6 +36,20 @@ module Karafka
|
|
|
31
36
|
@used = false
|
|
32
37
|
end
|
|
33
38
|
|
|
39
|
+
# Trigger method running after consumer is fully initialized.
|
|
40
|
+
#
|
|
41
|
+
# @private
|
|
42
|
+
def on_initialized
|
|
43
|
+
handle_initialized
|
|
44
|
+
rescue StandardError => e
|
|
45
|
+
monitor.instrument(
|
|
46
|
+
'error.occurred',
|
|
47
|
+
error: e,
|
|
48
|
+
caller: self,
|
|
49
|
+
type: 'consumer.initialized.error'
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
34
53
|
# Can be used to run preparation code prior to the job being enqueued
|
|
35
54
|
#
|
|
36
55
|
# @private
|
|
@@ -57,6 +76,23 @@ module Karafka
|
|
|
57
76
|
handle_before_consume
|
|
58
77
|
end
|
|
59
78
|
|
|
79
|
+
# Executes the default wrapping flow
|
|
80
|
+
#
|
|
81
|
+
# @private
|
|
82
|
+
#
|
|
83
|
+
# @param action [Symbol]
|
|
84
|
+
# @param block [Proc]
|
|
85
|
+
def on_wrap(action, &block)
|
|
86
|
+
handle_wrap(action, &block)
|
|
87
|
+
rescue StandardError => e
|
|
88
|
+
monitor.instrument(
|
|
89
|
+
'error.occurred',
|
|
90
|
+
error: e,
|
|
91
|
+
caller: self,
|
|
92
|
+
type: 'consumer.wrap.error'
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
60
96
|
# Executes the default consumer flow.
|
|
61
97
|
#
|
|
62
98
|
# @private
|
|
@@ -69,11 +105,11 @@ module Karafka
|
|
|
69
105
|
def on_consume
|
|
70
106
|
handle_consume
|
|
71
107
|
rescue StandardError => e
|
|
72
|
-
|
|
108
|
+
monitor.instrument(
|
|
73
109
|
'error.occurred',
|
|
74
110
|
error: e,
|
|
75
111
|
caller: self,
|
|
76
|
-
seek_offset:
|
|
112
|
+
seek_offset: seek_offset,
|
|
77
113
|
type: 'consumer.consume.error'
|
|
78
114
|
)
|
|
79
115
|
end
|
|
@@ -89,17 +125,35 @@ module Karafka
|
|
|
89
125
|
def on_after_consume
|
|
90
126
|
handle_after_consume
|
|
91
127
|
rescue StandardError => e
|
|
92
|
-
|
|
128
|
+
monitor.instrument(
|
|
93
129
|
'error.occurred',
|
|
94
130
|
error: e,
|
|
95
131
|
caller: self,
|
|
96
|
-
seek_offset:
|
|
132
|
+
seek_offset: seek_offset,
|
|
97
133
|
type: 'consumer.after_consume.error'
|
|
98
134
|
)
|
|
99
135
|
|
|
100
136
|
retry_after_pause
|
|
101
137
|
end
|
|
102
138
|
|
|
139
|
+
# Can be used to run code prior to scheduling of eofed execution
|
|
140
|
+
def on_before_schedule_eofed
|
|
141
|
+
handle_before_schedule_eofed
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Trigger method for running on eof without messages
|
|
145
|
+
def on_eofed
|
|
146
|
+
handle_eofed
|
|
147
|
+
rescue StandardError => e
|
|
148
|
+
monitor.instrument(
|
|
149
|
+
'error.occurred',
|
|
150
|
+
error: e,
|
|
151
|
+
caller: self,
|
|
152
|
+
seek_offset: seek_offset,
|
|
153
|
+
type: 'consumer.eofed.error'
|
|
154
|
+
)
|
|
155
|
+
end
|
|
156
|
+
|
|
103
157
|
# Can be used to run code prior to scheduling of idle execution
|
|
104
158
|
#
|
|
105
159
|
# @private
|
|
@@ -127,7 +181,7 @@ module Karafka
|
|
|
127
181
|
def on_revoked
|
|
128
182
|
handle_revoked
|
|
129
183
|
rescue StandardError => e
|
|
130
|
-
|
|
184
|
+
monitor.instrument(
|
|
131
185
|
'error.occurred',
|
|
132
186
|
error: e,
|
|
133
187
|
caller: self,
|
|
@@ -148,7 +202,7 @@ module Karafka
|
|
|
148
202
|
def on_shutdown
|
|
149
203
|
handle_shutdown
|
|
150
204
|
rescue StandardError => e
|
|
151
|
-
|
|
205
|
+
monitor.instrument(
|
|
152
206
|
'error.occurred',
|
|
153
207
|
error: e,
|
|
154
208
|
caller: self,
|
|
@@ -158,6 +212,15 @@ module Karafka
|
|
|
158
212
|
|
|
159
213
|
private
|
|
160
214
|
|
|
215
|
+
# Method called post-initialization of a consumer when all basic things are assigned.
|
|
216
|
+
# Since initialization via `#initialize` is complex and some states are set a bit later, this
|
|
217
|
+
# hook allows to initialize resources once at a time when topic, partition and other things
|
|
218
|
+
# are assigned to the consumer
|
|
219
|
+
#
|
|
220
|
+
# @note Please keep in mind that it will run many times when persistence is off. Basically once
|
|
221
|
+
# each batch.
|
|
222
|
+
def initialized; end
|
|
223
|
+
|
|
161
224
|
# Method that will perform business logic and on data received from Kafka (it will consume
|
|
162
225
|
# the data)
|
|
163
226
|
# @note This method needs to be implemented in a subclass. We stub it here as a failover if
|
|
@@ -166,6 +229,44 @@ module Karafka
|
|
|
166
229
|
raise NotImplementedError, 'Implement this in a subclass'
|
|
167
230
|
end
|
|
168
231
|
|
|
232
|
+
# This method can be redefined to build a wrapping API around user code + karafka flow control
|
|
233
|
+
# code starting from the user code (operations prior to that are not part of this).
|
|
234
|
+
# The wrapping relates to a single job flow.
|
|
235
|
+
#
|
|
236
|
+
# Karafka framework may require user configured "state" like for example a selected
|
|
237
|
+
# transactional producer that should be used not only by the user but also by the framework.
|
|
238
|
+
# By using this API user can checkout a producer and return it to the pool.
|
|
239
|
+
#
|
|
240
|
+
# @param _action [Symbol] what action are we wrapping. Useful if we want for example to only
|
|
241
|
+
# wrap the `:consume` action.
|
|
242
|
+
# @yield Runs the execution block
|
|
243
|
+
#
|
|
244
|
+
# @note User related errors should not leak to this level of execution. This should not be used
|
|
245
|
+
# for anything consumption related but only for setting up state that that Karafka code
|
|
246
|
+
# may need outside of user code.
|
|
247
|
+
#
|
|
248
|
+
# @example Redefine to use a producer from a pool for consume
|
|
249
|
+
# def wrap(action)
|
|
250
|
+
# # Do not checkout producer for any other actions
|
|
251
|
+
# return yield unless action == :consume
|
|
252
|
+
#
|
|
253
|
+
# default_producer = self.producer
|
|
254
|
+
#
|
|
255
|
+
# $producers.with do |producer|
|
|
256
|
+
# self.producer = producer
|
|
257
|
+
# yield
|
|
258
|
+
# end
|
|
259
|
+
#
|
|
260
|
+
# self.producer = default_producer
|
|
261
|
+
# end
|
|
262
|
+
def wrap(_action)
|
|
263
|
+
yield
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Method that will be executed when a given topic partition reaches eof without any new
|
|
267
|
+
# incoming messages alongside
|
|
268
|
+
def eofed; end
|
|
269
|
+
|
|
169
270
|
# Method that will be executed when a given topic partition is revoked. You can use it for
|
|
170
271
|
# some teardown procedures (closing file handler, etc).
|
|
171
272
|
def revoked; end
|
|
@@ -208,7 +309,7 @@ module Karafka
|
|
|
208
309
|
# Indicate, that user took a manual action of pausing
|
|
209
310
|
coordinator.manual_pause if manual_pause
|
|
210
311
|
|
|
211
|
-
|
|
312
|
+
monitor.instrument(
|
|
212
313
|
'consumer.consuming.pause',
|
|
213
314
|
caller: self,
|
|
214
315
|
manual: manual_pause,
|
|
@@ -244,15 +345,25 @@ module Karafka
|
|
|
244
345
|
# @note Please note, that if you are seeking to a time offset, getting the offset is blocking
|
|
245
346
|
def seek(offset, manual_seek = true, reset_offset: false)
|
|
246
347
|
coordinator.manual_seek if manual_seek
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
offset
|
|
254
|
-
)
|
|
348
|
+
self.seek_offset = nil if reset_offset
|
|
349
|
+
|
|
350
|
+
message = Karafka::Messages::Seek.new(
|
|
351
|
+
topic.name,
|
|
352
|
+
partition,
|
|
353
|
+
offset
|
|
255
354
|
)
|
|
355
|
+
|
|
356
|
+
monitor.instrument(
|
|
357
|
+
'consumer.consuming.seek',
|
|
358
|
+
caller: self,
|
|
359
|
+
topic: topic.name,
|
|
360
|
+
partition: partition,
|
|
361
|
+
message: message,
|
|
362
|
+
manual_seek: manual_seek,
|
|
363
|
+
reset_offset: reset_offset
|
|
364
|
+
) do
|
|
365
|
+
client.seek(message)
|
|
366
|
+
end
|
|
256
367
|
end
|
|
257
368
|
|
|
258
369
|
# @return [Boolean] true if partition was revoked from the current consumer
|
|
@@ -286,16 +397,16 @@ module Karafka
|
|
|
286
397
|
# Pauses the processing from the last offset to retry on given message
|
|
287
398
|
# @private
|
|
288
399
|
def retry_after_pause
|
|
289
|
-
pause(
|
|
400
|
+
pause(seek_offset, nil, false)
|
|
290
401
|
|
|
291
402
|
# Instrumentation needs to run **after** `#pause` invocation because we rely on the states
|
|
292
403
|
# set by `#pause`
|
|
293
|
-
|
|
404
|
+
monitor.instrument(
|
|
294
405
|
'consumer.consuming.retry',
|
|
295
406
|
caller: self,
|
|
296
407
|
topic: topic.name,
|
|
297
408
|
partition: partition,
|
|
298
|
-
offset:
|
|
409
|
+
offset: seek_offset,
|
|
299
410
|
timeout: coordinator.pause_tracker.current_timeout,
|
|
300
411
|
attempt: attempt
|
|
301
412
|
)
|