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
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This code is part of Karafka Pro, a commercial component not licensed under LGPL.
|
|
4
|
+
# See LICENSE for details.
|
|
5
|
+
|
|
6
|
+
module Karafka
|
|
7
|
+
module Pro
|
|
8
|
+
module ScheduledMessages
|
|
9
|
+
# Proxy used to wrap the scheduled messages with the correct dispatch envelope.
|
|
10
|
+
# Each message that goes to the scheduler topic needs to have specific headers and other
|
|
11
|
+
# details that are required by the system so we know how and when to dispatch it.
|
|
12
|
+
#
|
|
13
|
+
# Each message that goes to the proxy topic needs to have a unique key. We inject those
|
|
14
|
+
# automatically unless user provides one in an envelope. Since we want to make sure, that
|
|
15
|
+
# the messages dispatched by the user all go to the same partition (if with same key), we
|
|
16
|
+
# inject a partition_key based on the user key or other details if present. That allows us
|
|
17
|
+
# to make sure, that they will always go to the same partition on our side.
|
|
18
|
+
#
|
|
19
|
+
# This wrapper validates the initial message that user wants to send in the future, as well
|
|
20
|
+
# as the envelope and specific requirements for a message to be send in the future
|
|
21
|
+
module Proxy
|
|
22
|
+
# General WaterDrop message contract. Before we envelop a message, we need to be certain
|
|
23
|
+
# it is correct, hence we use this contract.
|
|
24
|
+
MSG_CONTRACT = ::WaterDrop::Contracts::Message.new(
|
|
25
|
+
# Payload size is a subject to the target producer dispatch validation, so we set it
|
|
26
|
+
# to 100MB basically to ignore it here.
|
|
27
|
+
max_payload_size: 104_857_600
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Post-rebind contract to ensure, that user provided all needed details that would allow
|
|
31
|
+
# the system to operate correctly
|
|
32
|
+
POST_CONTRACT = Contracts::Message.new
|
|
33
|
+
|
|
34
|
+
# Attributes used to build a partition key for the schedules topic dispatch of a given
|
|
35
|
+
# message. We use this order as this order describes the priority of usage.
|
|
36
|
+
PARTITION_KEY_BASE_ATTRIBUTES = %i[
|
|
37
|
+
partition
|
|
38
|
+
partition_key
|
|
39
|
+
].freeze
|
|
40
|
+
|
|
41
|
+
private_constant :MSG_CONTRACT, :POST_CONTRACT, :PARTITION_KEY_BASE_ATTRIBUTES
|
|
42
|
+
|
|
43
|
+
class << self
|
|
44
|
+
# Generates a schedule message envelope wrapping the original dispatch
|
|
45
|
+
#
|
|
46
|
+
# @param message [Hash] message hash of a message that would originally go to WaterDrop
|
|
47
|
+
# producer directly.
|
|
48
|
+
# @param epoch [Integer] time in the future (or now) when dispatch this message in the
|
|
49
|
+
# Unix epoch timestamp
|
|
50
|
+
# @param envelope [Hash] Special details that the envelop needs to have, like a unique
|
|
51
|
+
# key. If unique key is not provided we build a random unique one and use a
|
|
52
|
+
# partition_key based on the original message key (if present) to ensure that all
|
|
53
|
+
# relevant messages are dispatched to the same topic partition.
|
|
54
|
+
# @return [Hash] dispatched message wrapped with an envelope
|
|
55
|
+
#
|
|
56
|
+
# @note This proxy does **not** inject the dispatched messages topic unless provided in
|
|
57
|
+
# the envelope. That's because user can have multiple scheduled messages topics to
|
|
58
|
+
# group outgoing messages, etc.
|
|
59
|
+
def schedule(message:, epoch:, envelope: {})
|
|
60
|
+
# We need to ensure that the message we want to proxy is fully legit. Otherwise, since
|
|
61
|
+
# we envelope details like target topic, we could end up having incorrect data to
|
|
62
|
+
# schedule
|
|
63
|
+
MSG_CONTRACT.validate!(message, WaterDrop::Errors::MessageInvalidError)
|
|
64
|
+
|
|
65
|
+
headers = (message[:headers] || {}).merge(
|
|
66
|
+
'schedule_schema_version' => ScheduledMessages::SCHEMA_VERSION,
|
|
67
|
+
'schedule_target_epoch' => epoch.to_i.to_s,
|
|
68
|
+
'schedule_source_type' => 'schedule'
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
export(headers, message, :topic)
|
|
72
|
+
export(headers, message, :partition)
|
|
73
|
+
export(headers, message, :key)
|
|
74
|
+
export(headers, message, :partition_key)
|
|
75
|
+
|
|
76
|
+
proxy_message = {
|
|
77
|
+
payload: message[:payload],
|
|
78
|
+
headers: headers
|
|
79
|
+
}.merge(envelope)
|
|
80
|
+
|
|
81
|
+
enrich(proxy_message, message)
|
|
82
|
+
validate!(proxy_message)
|
|
83
|
+
|
|
84
|
+
proxy_message
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Generates a tombstone message to cancel already scheduled message dispatch
|
|
88
|
+
# @param key [String] key used by the original message as a unique identifier
|
|
89
|
+
# @param envelope [Hash] Special details that can identify the message location like
|
|
90
|
+
# topic and partition (if used) so the cancellation goes to the correct location.
|
|
91
|
+
# @return [Hash] cancellation message
|
|
92
|
+
#
|
|
93
|
+
# @note Technically it is a tombstone but we differentiate just for the sake of ability
|
|
94
|
+
# to debug stuff if needed
|
|
95
|
+
def cancel(key:, envelope: {})
|
|
96
|
+
proxy_message = {
|
|
97
|
+
key: key,
|
|
98
|
+
payload: nil,
|
|
99
|
+
headers: {
|
|
100
|
+
'schedule_schema_version' => ScheduledMessages::SCHEMA_VERSION,
|
|
101
|
+
'schedule_source_type' => 'cancel'
|
|
102
|
+
}
|
|
103
|
+
}.merge(envelope)
|
|
104
|
+
|
|
105
|
+
# Ensure user provided envelope is with all expected details
|
|
106
|
+
validate!(proxy_message)
|
|
107
|
+
|
|
108
|
+
proxy_message
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Builds tombstone with the dispatched message details. Those details can be used
|
|
112
|
+
# in Web UI, etc when analyzing dispatches.
|
|
113
|
+
# @param message [Karafka::Messages::Message] message we want to tombstone
|
|
114
|
+
# topic and partition (if used) so the cancellation goes to the correct location.
|
|
115
|
+
def tombstone(message:)
|
|
116
|
+
{
|
|
117
|
+
key: message.key,
|
|
118
|
+
payload: nil,
|
|
119
|
+
topic: message.topic,
|
|
120
|
+
partition: message.partition,
|
|
121
|
+
headers: message.raw_headers.merge(
|
|
122
|
+
'schedule_schema_version' => ScheduledMessages::SCHEMA_VERSION,
|
|
123
|
+
'schedule_source_type' => 'tombstone',
|
|
124
|
+
'schedule_source_offset' => message.offset.to_s
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
# Transfers the message key attributes into headers. Since we need to have our own
|
|
132
|
+
# envelope key and other details, we transfer the original message details into headers
|
|
133
|
+
# so we can re-use them when we dispatch the scheduled messages at an appropriate time
|
|
134
|
+
#
|
|
135
|
+
# @param headers [Hash] envelope headers to which we will add appropriate attribute
|
|
136
|
+
# @param message [Hash] original user message
|
|
137
|
+
# @param attribute [Symbol] attribute we're interested in exporting to headers
|
|
138
|
+
# @note Modifies headers in place
|
|
139
|
+
def export(headers, message, attribute)
|
|
140
|
+
return unless message.key?(attribute)
|
|
141
|
+
|
|
142
|
+
headers["schedule_target_#{attribute}"] = message.fetch(attribute).to_s
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Adds the key and (if applicable) partition key to ensure, that related messages that
|
|
146
|
+
# user wants to dispatch in the future, are all in the same topic partition.
|
|
147
|
+
# @param proxy_message [Hash] our message envelope
|
|
148
|
+
# @param message [Hash] user original message
|
|
149
|
+
# @note Modifies `proxy_message` in place
|
|
150
|
+
def enrich(proxy_message, message)
|
|
151
|
+
# If there is an envelope message key already, nothing needed
|
|
152
|
+
return if proxy_message.key?(:key)
|
|
153
|
+
|
|
154
|
+
proxy_message[:key] = "#{message[:topic]}-#{SecureRandom.uuid}"
|
|
155
|
+
|
|
156
|
+
PARTITION_KEY_BASE_ATTRIBUTES.each do |attribute|
|
|
157
|
+
next unless message.key?(attribute)
|
|
158
|
+
# Do not overwrite if explicitely set by the user
|
|
159
|
+
next if proxy_message.key?(attribute)
|
|
160
|
+
|
|
161
|
+
proxy_message[:partition_key] = message.fetch(attribute).to_s
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Final validations to make sure all user provided extra data and what we have built
|
|
166
|
+
# complies with our requirements
|
|
167
|
+
# @param proxy_message [Hash] our message envelope
|
|
168
|
+
def validate!(proxy_message)
|
|
169
|
+
POST_CONTRACT.validate!(proxy_message)
|
|
170
|
+
# After proxy specific validations we also ensure, that the final form is correct
|
|
171
|
+
MSG_CONTRACT.validate!(proxy_message, WaterDrop::Errors::MessageInvalidError)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This code is part of Karafka Pro, a commercial component not licensed under LGPL.
|
|
4
|
+
# See LICENSE for details.
|
|
5
|
+
|
|
6
|
+
module Karafka
|
|
7
|
+
module Pro
|
|
8
|
+
module ScheduledMessages
|
|
9
|
+
# Validator that checks if we can process this scheduled message
|
|
10
|
+
# If we encounter message that has a schema version higher than our process is aware of
|
|
11
|
+
# we raise and error and do not process. This is to make sure we do not deal with messages
|
|
12
|
+
# that are not compatible in case of schema changes.
|
|
13
|
+
module SchemaValidator
|
|
14
|
+
class << self
|
|
15
|
+
# Check if we can work with this schema message and raise error if not.
|
|
16
|
+
#
|
|
17
|
+
# @param message [Karafka::Messages::Message]
|
|
18
|
+
def call(message)
|
|
19
|
+
message_version = message.headers['schedule_schema_version']
|
|
20
|
+
|
|
21
|
+
return if message_version <= ScheduledMessages::SCHEMA_VERSION
|
|
22
|
+
|
|
23
|
+
raise Errors::IncompatibleSchemaError, message_version
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This code is part of Karafka Pro, a commercial component not licensed under LGPL.
|
|
4
|
+
# See LICENSE for details.
|
|
5
|
+
|
|
6
|
+
module Karafka
|
|
7
|
+
module Pro
|
|
8
|
+
module ScheduledMessages
|
|
9
|
+
# Serializers used to build payloads (if applicable) for dispatch
|
|
10
|
+
# @note We only deal with states payload. Other payloads are not ours but end users.
|
|
11
|
+
class Serializer
|
|
12
|
+
include ::Karafka::Core::Helpers::Time
|
|
13
|
+
|
|
14
|
+
# @param tracker [Tracker] tracker based on which we build the state
|
|
15
|
+
# @return [String] compressed payload with the state details
|
|
16
|
+
def state(tracker)
|
|
17
|
+
data = {
|
|
18
|
+
schema_version: ScheduledMessages::STATES_SCHEMA_VERSION,
|
|
19
|
+
dispatched_at: float_now,
|
|
20
|
+
state: tracker.state,
|
|
21
|
+
daily: tracker.daily
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
compress(
|
|
25
|
+
serialize(data)
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
# @param hash [Hash] hash to cast to json
|
|
32
|
+
# @return [String] json hash
|
|
33
|
+
def serialize(hash)
|
|
34
|
+
hash.to_json
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Compresses the provided data
|
|
38
|
+
#
|
|
39
|
+
# @param data [String] data to compress
|
|
40
|
+
# @return [String] compressed data
|
|
41
|
+
def compress(data)
|
|
42
|
+
Zlib::Deflate.deflate(data)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This code is part of Karafka Pro, a commercial component not licensed under LGPL.
|
|
4
|
+
# See LICENSE for details.
|
|
5
|
+
|
|
6
|
+
module Karafka
|
|
7
|
+
module Pro
|
|
8
|
+
module ScheduledMessages
|
|
9
|
+
# Setup and config related recurring tasks components
|
|
10
|
+
module Setup
|
|
11
|
+
# Config for recurring tasks
|
|
12
|
+
class Config
|
|
13
|
+
extend ::Karafka::Core::Configurable
|
|
14
|
+
|
|
15
|
+
setting(:consumer_class, default: Consumer)
|
|
16
|
+
setting(:group_id, default: 'karafka_scheduled_messages')
|
|
17
|
+
|
|
18
|
+
# By default we will run the scheduling every 15 seconds since we provide a minute-based
|
|
19
|
+
# precision. Can be increased when having dedicated processes to run this. Lower values
|
|
20
|
+
# mean more frequent execution on low-throughput topics meaning higher precision.
|
|
21
|
+
setting(:interval, default: 15_000)
|
|
22
|
+
|
|
23
|
+
# How many messages should be flush in one go from the dispatcher at most. If we have
|
|
24
|
+
# more messages to dispatch, they will be chunked.
|
|
25
|
+
setting(:flush_batch_size, default: 1_000)
|
|
26
|
+
|
|
27
|
+
# Producer to use. By default uses default Karafka producer.
|
|
28
|
+
setting(
|
|
29
|
+
:producer,
|
|
30
|
+
constructor: -> { ::Karafka.producer },
|
|
31
|
+
lazy: true
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Class we use to dispatch messages
|
|
35
|
+
setting(:dispatcher_class, default: Dispatcher)
|
|
36
|
+
|
|
37
|
+
# Postfix for the states topic to build the states based on the group name + postfix
|
|
38
|
+
setting(:states_postfix, default: '_states')
|
|
39
|
+
|
|
40
|
+
setting(:deserializers) do
|
|
41
|
+
# Deserializer for schedules messages to convert epochs
|
|
42
|
+
setting(:headers, default: Deserializers::Headers.new)
|
|
43
|
+
# Only applicable to states
|
|
44
|
+
setting(:payload, default: Deserializers::Payload.new)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
configure
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This code is part of Karafka Pro, a commercial component not licensed under LGPL.
|
|
4
|
+
# See LICENSE for details.
|
|
5
|
+
|
|
6
|
+
module Karafka
|
|
7
|
+
module Pro
|
|
8
|
+
module ScheduledMessages
|
|
9
|
+
# Represents the loading/bootstrapping state of the given topic partition
|
|
10
|
+
#
|
|
11
|
+
# Bootstrapping can be in the following states:
|
|
12
|
+
# - fresh - when we got an assignment but we did not load the schedule yet
|
|
13
|
+
# - loading - when we are in the process of bootstrapping the daily state and we consume
|
|
14
|
+
# historical messages to build the needed schedules.
|
|
15
|
+
# - loaded - state in which we finished loading all the schedules and we can dispatch
|
|
16
|
+
# messages when the time comes and we can process real-time incoming schedules and
|
|
17
|
+
# changes to schedules as they appear in the stream.
|
|
18
|
+
class State
|
|
19
|
+
# @param loaded [nil, false, true] is the state loaded or not yet. `nil` indicates, it is
|
|
20
|
+
# a fresh, pre-seek state.
|
|
21
|
+
def initialize(loaded = nil)
|
|
22
|
+
@loaded = loaded
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @return [Boolean] are we in a fresh, pre-bootstrap state
|
|
26
|
+
def fresh?
|
|
27
|
+
@loaded.nil?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Marks the current state as fully loaded
|
|
31
|
+
def loaded!
|
|
32
|
+
@loaded = true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [Boolean] are we in a loaded state
|
|
36
|
+
def loaded?
|
|
37
|
+
@loaded == true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @return [String] current state string representation
|
|
41
|
+
def to_s
|
|
42
|
+
case @loaded
|
|
43
|
+
when nil
|
|
44
|
+
'fresh'
|
|
45
|
+
when false
|
|
46
|
+
'loading'
|
|
47
|
+
when true
|
|
48
|
+
'loaded'
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This code is part of Karafka Pro, a commercial component not licensed under LGPL.
|
|
4
|
+
# See LICENSE for details.
|
|
5
|
+
|
|
6
|
+
module Karafka
|
|
7
|
+
module Pro
|
|
8
|
+
module ScheduledMessages
|
|
9
|
+
# Tracks basic state and metrics about schedules to be dispatched
|
|
10
|
+
#
|
|
11
|
+
# It provides accurate today dispatch taken from daily buffer and estimates for future days
|
|
12
|
+
class Tracker
|
|
13
|
+
# @return [Hash<String, Integer>]
|
|
14
|
+
attr_reader :daily
|
|
15
|
+
|
|
16
|
+
# @return [String] current state
|
|
17
|
+
attr_accessor :state
|
|
18
|
+
|
|
19
|
+
def initialize
|
|
20
|
+
@daily = Hash.new { |h, k| h[k] = 0 }
|
|
21
|
+
@created_at = Time.now.to_i
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Accurate (because coming from daily buffer) number of things to schedule
|
|
25
|
+
#
|
|
26
|
+
# @param sum [Integer]
|
|
27
|
+
def today=(sum)
|
|
28
|
+
@daily[epoch_to_date(@created_at)] = sum
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Tracks message dispatch
|
|
32
|
+
#
|
|
33
|
+
# It is only relevant for future days as for today we use accurate metrics from the daily
|
|
34
|
+
# buffer
|
|
35
|
+
#
|
|
36
|
+
# @param message [Karafka::Messages::Message] schedule message. Should **not** be a
|
|
37
|
+
# tombstone message. Tombstone messages cancellations are not tracked because it would
|
|
38
|
+
# drastically increase complexity. For given day we use the accurate counter and for
|
|
39
|
+
# future days we use estimates.
|
|
40
|
+
def track(message)
|
|
41
|
+
epoch = message.headers['schedule_target_epoch']
|
|
42
|
+
|
|
43
|
+
@daily[epoch_to_date(epoch)] += 1
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# @param epoch [Integer] epoch time
|
|
49
|
+
# @return [String] epoch matching date
|
|
50
|
+
def epoch_to_date(epoch)
|
|
51
|
+
Time.at(epoch).utc.to_date.to_s
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This code is part of Karafka Pro, a commercial component not licensed under LGPL.
|
|
4
|
+
# See LICENSE for details.
|
|
5
|
+
|
|
6
|
+
module Karafka
|
|
7
|
+
module Pro
|
|
8
|
+
# This feature allows for proxying messages via a special topic that can dispatch them
|
|
9
|
+
# at a later time, hence scheduled messages. Such messages need to have a special format
|
|
10
|
+
# but aside from that they are regular Kafka messages.
|
|
11
|
+
#
|
|
12
|
+
# This work was conceptually inspired by the Go scheduler:
|
|
13
|
+
# https://github.com/etf1/kafka-message-scheduler though I did not look at the implementation
|
|
14
|
+
# itself. Just the concept of daily in-memory scheduling.
|
|
15
|
+
module ScheduledMessages
|
|
16
|
+
# Version of the schema we use for envelops in scheduled messages.
|
|
17
|
+
# We use it to detect any potential upgrades similar to other components of Karafka and to
|
|
18
|
+
# stop processing of incompatible versions
|
|
19
|
+
SCHEMA_VERSION = '1.0.0'
|
|
20
|
+
|
|
21
|
+
# Version of the states schema. Used to publish per partition simple aggregated metrics
|
|
22
|
+
# that can be used for schedules reporting
|
|
23
|
+
STATES_SCHEMA_VERSION = '1.0.0'
|
|
24
|
+
|
|
25
|
+
class << self
|
|
26
|
+
# Runs the `Proxy.call`
|
|
27
|
+
# @param kwargs [Hash] things requested by the proxy
|
|
28
|
+
# @return [Hash] message wrapped with the scheduled message envelope
|
|
29
|
+
def schedule(**kwargs)
|
|
30
|
+
Proxy.schedule(**kwargs)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Generates a tombstone message to cancel given dispatch (if not yet happened)
|
|
34
|
+
# @param kwargs [Hash] things requested by the proxy
|
|
35
|
+
# @return [Hash] tombstone cancelling message
|
|
36
|
+
def cancel(**kwargs)
|
|
37
|
+
Proxy.cancel(**kwargs)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Below are private APIs
|
|
41
|
+
|
|
42
|
+
# Sets up additional config scope, validations and other things
|
|
43
|
+
#
|
|
44
|
+
# @param config [Karafka::Core::Configurable::Node] root node config
|
|
45
|
+
def pre_setup(config)
|
|
46
|
+
# Expand the config with this feature specific stuff
|
|
47
|
+
config.instance_eval do
|
|
48
|
+
setting(:scheduled_messages, default: Setup::Config.config)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @param config [Karafka::Core::Configurable::Node] root node config
|
|
53
|
+
def post_setup(config)
|
|
54
|
+
RecurringTasks::Contracts::Config.new.validate!(config.to_h)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# This
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# All of the commercial components are present in the lib/karafka/pro directory of this
|
|
7
|
-
# repository and their usage requires commercial license agreement.
|
|
8
|
-
#
|
|
9
|
-
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
10
|
-
#
|
|
11
|
-
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
|
12
|
-
# your code to Maciej Mensfeld.
|
|
3
|
+
# This code is part of Karafka Pro, a commercial component not licensed under LGPL.
|
|
4
|
+
# See LICENSE for details.
|
|
13
5
|
|
|
14
6
|
module Karafka
|
|
15
7
|
module Pro
|
|
@@ -15,6 +15,13 @@ module Karafka
|
|
|
15
15
|
|
|
16
16
|
attr_reader :pause_tracker, :seek_offset, :topic, :partition
|
|
17
17
|
|
|
18
|
+
# This can be set directly on the listener because it can be triggered on first run without
|
|
19
|
+
# any messages
|
|
20
|
+
attr_accessor :eofed
|
|
21
|
+
|
|
22
|
+
# Last polled at time set based on the incoming last poll time
|
|
23
|
+
attr_accessor :last_polled_at
|
|
24
|
+
|
|
18
25
|
def_delegators :@pause_tracker, :attempt, :paused?
|
|
19
26
|
|
|
20
27
|
# @param topic [Karafka::Routing::Topic]
|
|
@@ -32,7 +39,9 @@ module Karafka
|
|
|
32
39
|
@mutex = Mutex.new
|
|
33
40
|
@marked = false
|
|
34
41
|
@failure = false
|
|
42
|
+
@eofed = false
|
|
35
43
|
@changed_at = monotonic_now
|
|
44
|
+
@last_polled_at = @changed_at
|
|
36
45
|
end
|
|
37
46
|
|
|
38
47
|
# Starts the coordinator for given consumption jobs
|
|
@@ -146,6 +155,11 @@ module Karafka
|
|
|
146
155
|
@revoked
|
|
147
156
|
end
|
|
148
157
|
|
|
158
|
+
# @return [Boolean] did we reach end of partition when polling data
|
|
159
|
+
def eofed?
|
|
160
|
+
@eofed
|
|
161
|
+
end
|
|
162
|
+
|
|
149
163
|
# @return [Boolean] was the new seek offset assigned at least once. This is needed because
|
|
150
164
|
# by default we assign seek offset of a first message ever, however this is insufficient
|
|
151
165
|
# for DLQ in a scenario where the first message would be broken. We would never move
|
|
@@ -81,6 +81,13 @@ module Karafka
|
|
|
81
81
|
consumer.on_before_consume
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
# Runs the wrap/around execution context appropriate for a given action
|
|
85
|
+
# @param action [Symbol] action execution wrapped with our block
|
|
86
|
+
# @param block [Proc] execution context
|
|
87
|
+
def wrap(action, &block)
|
|
88
|
+
consumer.on_wrap(action, &block)
|
|
89
|
+
end
|
|
90
|
+
|
|
84
91
|
# Runs consumer data processing against given batch and handles failures and errors.
|
|
85
92
|
def consume
|
|
86
93
|
# We run the consumer client logic...
|
|
@@ -104,6 +111,18 @@ module Karafka
|
|
|
104
111
|
consumer.on_idle
|
|
105
112
|
end
|
|
106
113
|
|
|
114
|
+
# Runs the code needed before eofed work is scheduled
|
|
115
|
+
def before_schedule_eofed
|
|
116
|
+
consumer.on_before_schedule_eofed
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Runs consumed eofed operation.
|
|
120
|
+
# This may run even when there were no messages received prior. This will however not
|
|
121
|
+
# run when eof is received together with messages as in such case `#consume` will run
|
|
122
|
+
def eofed
|
|
123
|
+
consumer.on_eofed
|
|
124
|
+
end
|
|
125
|
+
|
|
107
126
|
# Runs code needed before revoked job is scheduled
|
|
108
127
|
def before_schedule_revoked
|
|
109
128
|
consumer.on_before_schedule_revoked if @consumer
|
|
@@ -162,13 +181,22 @@ module Karafka
|
|
|
162
181
|
expansions.each { |expansion| consumer.singleton_class.include(expansion) }
|
|
163
182
|
|
|
164
183
|
consumer.client = @client
|
|
165
|
-
consumer.producer = ::Karafka::App.producer
|
|
166
184
|
consumer.coordinator = @coordinator
|
|
185
|
+
# We assign producer only when not available already. It may already be available if
|
|
186
|
+
# user redefined the `#producer` method for example. This can be useful for example when
|
|
187
|
+
# having a multi-cluster setup and using a totally custom producer
|
|
188
|
+
consumer.producer ||= ::Karafka::App.producer
|
|
167
189
|
# Since we have some message-less flows (idle, etc), we initialize consumer with empty
|
|
168
190
|
# messages set. In production we have persistent consumers, so this is not a performance
|
|
169
191
|
# overhead as this will happen only once per consumer lifetime
|
|
170
192
|
consumer.messages = empty_messages
|
|
171
193
|
|
|
194
|
+
# Run the post-initialization hook for users that need to run some actions when consumer
|
|
195
|
+
# is built and ready (all basic state and info).
|
|
196
|
+
# Users should **not** overwrite the `#initialize` because it won't have all the needed
|
|
197
|
+
# data assigned yet.
|
|
198
|
+
consumer.on_initialized
|
|
199
|
+
|
|
172
200
|
consumer
|
|
173
201
|
end
|
|
174
202
|
end
|
|
@@ -15,6 +15,11 @@ module Karafka
|
|
|
15
15
|
|
|
16
16
|
attr_reader :executor
|
|
17
17
|
|
|
18
|
+
class << self
|
|
19
|
+
# @return [Symbol] Job matching appropriate action
|
|
20
|
+
attr_accessor :action
|
|
21
|
+
end
|
|
22
|
+
|
|
18
23
|
# Creates a new job instance
|
|
19
24
|
def initialize
|
|
20
25
|
# All jobs are blocking by default and they can release the lock when blocking operations
|
|
@@ -23,6 +28,14 @@ module Karafka
|
|
|
23
28
|
@status = :pending
|
|
24
29
|
end
|
|
25
30
|
|
|
31
|
+
# Runs the wrap/around job hook within which the rest of the flow happens
|
|
32
|
+
# @param block [Proc] whole user related processing flow
|
|
33
|
+
# @note We inject the action name so user can decide whether to run custom logic on a
|
|
34
|
+
# given action or not.
|
|
35
|
+
def wrap(&block)
|
|
36
|
+
executor.wrap(self.class.action, &block)
|
|
37
|
+
end
|
|
38
|
+
|
|
26
39
|
# When redefined can run any code prior to the job being scheduled
|
|
27
40
|
# @note This will run in the listener thread and not in the worker
|
|
28
41
|
def before_schedule
|
|
@@ -9,6 +9,8 @@ module Karafka
|
|
|
9
9
|
# @return [Array<Rdkafka::Consumer::Message>] array with messages
|
|
10
10
|
attr_reader :messages
|
|
11
11
|
|
|
12
|
+
self.action = :consume
|
|
13
|
+
|
|
12
14
|
# @param executor [Karafka::Processing::Executor] executor that is suppose to run a given
|
|
13
15
|
# job
|
|
14
16
|
# @param messages [Karafka::Messages::Messages] karafka messages batch
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Karafka
|
|
4
|
+
module Processing
|
|
5
|
+
module Jobs
|
|
6
|
+
# Job that runs the eofed operation when we receive eof without messages alongside.
|
|
7
|
+
class Eofed < Base
|
|
8
|
+
self.action = :eofed
|
|
9
|
+
|
|
10
|
+
# @param executor [Karafka::Processing::Executor] executor that is suppose to run the job
|
|
11
|
+
# @return [Eofed]
|
|
12
|
+
def initialize(executor)
|
|
13
|
+
@executor = executor
|
|
14
|
+
super()
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Runs code prior to scheduling this eofed job
|
|
18
|
+
def before_schedule
|
|
19
|
+
executor.before_schedule_eofed
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Runs the eofed job via an executor.
|
|
23
|
+
def call
|
|
24
|
+
executor.eofed
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -6,6 +6,8 @@ module Karafka
|
|
|
6
6
|
# Type of job that we may use to run some extra handling that happens without the user
|
|
7
7
|
# related lifecycle event like consumption, revocation, etc.
|
|
8
8
|
class Idle < Base
|
|
9
|
+
self.action = :idle
|
|
10
|
+
|
|
9
11
|
# @param executor [Karafka::Processing::Executor] executor that is suppose to run a given
|
|
10
12
|
# job on an active consumer
|
|
11
13
|
# @return [Shutdown]
|
|
@@ -5,6 +5,8 @@ module Karafka
|
|
|
5
5
|
module Jobs
|
|
6
6
|
# Job that runs the revoked operation when we loose a partition on a consumer that lost it.
|
|
7
7
|
class Revoked < Base
|
|
8
|
+
self.action = :revoked
|
|
9
|
+
|
|
8
10
|
# @param executor [Karafka::Processing::Executor] executor that is suppose to run the job
|
|
9
11
|
# @return [Revoked]
|
|
10
12
|
def initialize(executor)
|