karafka 2.5.9 → 2.6.0.beta1

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.
Files changed (471) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/certs/expired.txt +83 -0
  4. data/config/locales/errors.yml +17 -7
  5. data/karafka.gemspec +3 -3
  6. data/lib/active_job/queue_adapters/karafka_adapter.rb +1 -2
  7. data/lib/karafka/active_job/job_extensions.rb +1 -2
  8. data/lib/karafka/admin/configs/resource.rb +1 -2
  9. data/lib/karafka/admin/consumer_groups.rb +109 -98
  10. data/lib/karafka/admin/isolation_levels.rb +22 -0
  11. data/lib/karafka/admin/topics.rb +103 -8
  12. data/lib/karafka/admin.rb +59 -31
  13. data/lib/karafka/app.rb +16 -5
  14. data/lib/karafka/base_consumer.rb +2 -2
  15. data/lib/karafka/cli/contracts/server.rb +4 -4
  16. data/lib/karafka/cli/info.rb +1 -1
  17. data/lib/karafka/cli/topics/base.rb +10 -18
  18. data/lib/karafka/cli/topics/repartition.rb +1 -1
  19. data/lib/karafka/connection/client.rb +40 -9
  20. data/lib/karafka/connection/consumer_groups/rebalance_manager.rb +120 -0
  21. data/lib/karafka/connection/listener.rb +8 -7
  22. data/lib/karafka/connection/listeners_batch.rb +1 -1
  23. data/lib/karafka/connection/mode.rb +1 -2
  24. data/lib/karafka/connection/raw_messages_buffer.rb +0 -5
  25. data/lib/karafka/declaratives/builder.rb +65 -0
  26. data/lib/karafka/declaratives/contracts/topic.rb +28 -0
  27. data/lib/karafka/declaratives/repository.rb +52 -0
  28. data/lib/karafka/declaratives/topic.rb +100 -0
  29. data/lib/karafka/declaratives.rb +9 -0
  30. data/lib/karafka/helpers/interval_runner.rb +2 -2
  31. data/lib/karafka/instrumentation/assignments_tracker.rb +65 -2
  32. data/lib/karafka/instrumentation/callbacks/consumer_groups/error.rb +56 -0
  33. data/lib/karafka/instrumentation/callbacks/consumer_groups/rebalance.rb +93 -0
  34. data/lib/karafka/instrumentation/callbacks/consumer_groups/statistics.rb +59 -0
  35. data/lib/karafka/instrumentation/logger_listener.rb +27 -9
  36. data/lib/karafka/instrumentation/notifications.rb +2 -0
  37. data/lib/karafka/instrumentation/vendors/appsignal/metrics_listener.rb +14 -17
  38. data/lib/karafka/instrumentation/vendors/datadog/metrics_listener.rb +8 -9
  39. data/lib/karafka/instrumentation/vendors/kubernetes/base_listener.rb +7 -3
  40. data/lib/karafka/instrumentation/vendors/kubernetes/liveness_listener.rb +13 -10
  41. data/lib/karafka/licenser.rb +16 -3
  42. data/lib/karafka/pro/active_job/consumer.rb +1 -2
  43. data/lib/karafka/pro/active_job/dispatcher.rb +1 -2
  44. data/lib/karafka/pro/admin/recovery.rb +19 -19
  45. data/lib/karafka/pro/base_consumer.rb +3 -3
  46. data/lib/karafka/pro/cli/contracts/server.rb +5 -5
  47. data/lib/karafka/pro/cli/parallel_segments/base.rb +7 -7
  48. data/lib/karafka/pro/cli/parallel_segments/collapse.rb +4 -4
  49. data/lib/karafka/pro/cli/parallel_segments/distribute.rb +6 -6
  50. data/lib/karafka/pro/iterator/tpl_builder.rb +38 -18
  51. data/lib/karafka/pro/loader.rb +15 -12
  52. data/lib/karafka/pro/processing/consumer_groups/adaptive_iterator/consumer.rb +84 -0
  53. data/lib/karafka/pro/processing/consumer_groups/adaptive_iterator/tracker.rb +97 -0
  54. data/lib/karafka/pro/processing/consumer_groups/collapser.rb +84 -0
  55. data/lib/karafka/pro/processing/consumer_groups/coordinator.rb +202 -0
  56. data/lib/karafka/pro/processing/consumer_groups/coordinators/errors_tracker.rb +124 -0
  57. data/lib/karafka/pro/processing/consumer_groups/coordinators/filters_applier.rb +157 -0
  58. data/lib/karafka/pro/processing/consumer_groups/coordinators/virtual_offset_manager.rb +212 -0
  59. data/lib/karafka/pro/processing/{filters/expirer.rb → consumer_groups/executor.rb} +17 -31
  60. data/lib/karafka/pro/processing/{jobs/periodic.rb → consumer_groups/expansions_selector.rb} +18 -21
  61. data/lib/karafka/pro/processing/consumer_groups/filters/base.rb +103 -0
  62. data/lib/karafka/pro/processing/consumer_groups/filters/delayer.rb +92 -0
  63. data/lib/karafka/pro/processing/consumer_groups/filters/expirer.rb +78 -0
  64. data/lib/karafka/pro/processing/consumer_groups/filters/inline_insights_delayer.rb +99 -0
  65. data/lib/karafka/pro/processing/consumer_groups/filters/throttler.rb +106 -0
  66. data/lib/karafka/pro/processing/consumer_groups/filters/virtual_limiter.rb +79 -0
  67. data/lib/karafka/pro/processing/{jobs → consumer_groups/jobs}/consume_non_blocking.rb +21 -17
  68. data/lib/karafka/pro/processing/{virtual_partitions/distributors/consistent.rb → consumer_groups/jobs/eofed_non_blocking.rb} +16 -14
  69. data/lib/karafka/pro/processing/consumer_groups/jobs/periodic.rb +64 -0
  70. data/lib/karafka/pro/processing/{jobs → consumer_groups/jobs}/periodic_non_blocking.rb +16 -11
  71. data/lib/karafka/pro/processing/{jobs → consumer_groups/jobs}/revoked_non_blocking.rb +19 -15
  72. data/lib/karafka/pro/processing/consumer_groups/jobs_builder.rb +95 -0
  73. data/lib/karafka/pro/processing/consumer_groups/offset_metadata/consumer.rb +66 -0
  74. data/lib/karafka/pro/processing/consumer_groups/offset_metadata/fetcher.rb +154 -0
  75. data/lib/karafka/pro/processing/consumer_groups/offset_metadata/listener.rb +68 -0
  76. data/lib/karafka/pro/processing/consumer_groups/parallel_segments/filters/base.rb +102 -0
  77. data/lib/karafka/pro/processing/consumer_groups/parallel_segments/filters/default.rb +115 -0
  78. data/lib/karafka/pro/processing/consumer_groups/parallel_segments/filters/mom.rb +96 -0
  79. data/lib/karafka/pro/processing/consumer_groups/partitioner.rb +98 -0
  80. data/lib/karafka/pro/processing/consumer_groups/periodic_job/consumer.rb +90 -0
  81. data/lib/karafka/pro/processing/consumer_groups/piping/consumer.rb +154 -0
  82. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_ftr_lrj_mom.rb +93 -0
  83. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_ftr_lrj_mom_vp.rb +99 -0
  84. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_ftr_mom.rb +92 -0
  85. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_ftr_mom_vp.rb +90 -0
  86. data/lib/karafka/pro/processing/{strategies/aj/dlq_ftr_lrj_mom.rb → consumer_groups/strategies/aj/dlq_lrj_mom.rb} +37 -39
  87. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_lrj_mom_vp.rb +90 -0
  88. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_mom.rb +84 -0
  89. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_mom_vp.rb +89 -0
  90. data/lib/karafka/pro/processing/{strategies → consumer_groups/strategies}/aj/ftr_lrj_mom.rb +20 -15
  91. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/ftr_lrj_mom_vp.rb +91 -0
  92. data/lib/karafka/pro/processing/{strategies → consumer_groups/strategies}/aj/ftr_mom.rb +20 -15
  93. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/ftr_mom_vp.rb +80 -0
  94. data/lib/karafka/pro/processing/{strategies/mom/default.rb → consumer_groups/strategies/aj/lrj_mom.rb} +18 -22
  95. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/lrj_mom_vp.rb +106 -0
  96. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/mom.rb +58 -0
  97. data/lib/karafka/pro/processing/consumer_groups/strategies/aj/mom_vp.rb +74 -0
  98. data/lib/karafka/pro/processing/{strategies/lrj/vp.rb → consumer_groups/strategies/base.rb} +9 -14
  99. data/lib/karafka/pro/processing/consumer_groups/strategies/default.rb +421 -0
  100. data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/default.rb +285 -0
  101. data/lib/karafka/pro/processing/{strategies/dlq/lrj.rb → consumer_groups/strategies/dlq/ftr.rb} +30 -29
  102. data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_lrj.rb +95 -0
  103. data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_lrj_mom.rb +97 -0
  104. data/lib/karafka/pro/processing/{executor.rb → consumer_groups/strategies/dlq/ftr_lrj_mom_vp.rb} +26 -15
  105. data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_lrj_vp.rb +63 -0
  106. data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_mom.rb +97 -0
  107. data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_mom_vp.rb +63 -0
  108. data/lib/karafka/pro/{routing/features/patterns/patterns.rb → processing/consumer_groups/strategies/dlq/ftr_vp.rb} +22 -12
  109. data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/lrj.rb +83 -0
  110. data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/lrj_mom.rb +100 -0
  111. data/lib/karafka/pro/processing/{strategies → consumer_groups/strategies}/dlq/lrj_mom_vp.rb +18 -13
  112. data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/lrj_vp.rb +61 -0
  113. data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/mom.rb +96 -0
  114. data/lib/karafka/pro/processing/{strategies/lrj → consumer_groups/strategies/dlq}/mom_vp.rb +19 -15
  115. data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/vp.rb +62 -0
  116. data/lib/karafka/pro/processing/consumer_groups/strategies/ftr/default.rb +146 -0
  117. data/lib/karafka/pro/processing/{strategies/mom/ftr.rb → consumer_groups/strategies/ftr/vp.rb} +20 -28
  118. data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/default.rb +119 -0
  119. data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/ftr.rb +94 -0
  120. data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/ftr_mom.rb +92 -0
  121. data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/ftr_mom_vp.rb +62 -0
  122. data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/ftr_vp.rb +61 -0
  123. data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/mom.rb +101 -0
  124. data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/mom_vp.rb +60 -0
  125. data/lib/karafka/pro/processing/{strategies/mom → consumer_groups/strategies/lrj}/vp.rb +18 -12
  126. data/lib/karafka/pro/processing/{strategies/aj/mom_vp.rb → consumer_groups/strategies/mom/default.rb} +22 -23
  127. data/lib/karafka/pro/processing/{strategies/aj/ftr_mom_vp.rb → consumer_groups/strategies/mom/ftr.rb} +28 -28
  128. data/lib/karafka/pro/processing/{virtual_partitions/distributors/base.rb → consumer_groups/strategies/mom/ftr_vp.rb} +19 -14
  129. data/lib/karafka/pro/processing/{strategies/aj/mom.rb → consumer_groups/strategies/mom/vp.rb} +16 -12
  130. data/lib/karafka/pro/processing/consumer_groups/strategies/vp/default.rb +197 -0
  131. data/lib/karafka/pro/processing/consumer_groups/strategy_selector.rb +106 -0
  132. data/lib/karafka/pro/processing/consumer_groups/subscription_groups_coordinator.rb +73 -0
  133. data/lib/karafka/pro/processing/consumer_groups/virtual_partitions/distributors/balanced.rb +82 -0
  134. data/lib/karafka/pro/processing/consumer_groups/virtual_partitions/distributors/base.rb +59 -0
  135. data/lib/karafka/pro/processing/{strategies/dlq/ftr.rb → consumer_groups/virtual_partitions/distributors/consistent.rb} +18 -33
  136. data/lib/karafka/pro/processing/filters/base.rb +3 -61
  137. data/lib/karafka/pro/processing/partitioner.rb +2 -57
  138. data/lib/karafka/pro/processing/schedulers/base.rb +10 -6
  139. data/lib/karafka/pro/processing/schedulers/default.rb +6 -5
  140. data/lib/karafka/pro/recurring_tasks/executor.rb +1 -2
  141. data/lib/karafka/pro/routing/features/{active_job → consumer_groups/active_job}/builder.rb +20 -18
  142. data/lib/karafka/pro/routing/features/{inline_insights/config.rb → consumer_groups/active_job.rb} +5 -9
  143. data/lib/karafka/pro/routing/features/consumer_groups/adaptive_iterator/config.rb +53 -0
  144. data/lib/karafka/pro/routing/features/consumer_groups/adaptive_iterator/contracts/topic.rb +91 -0
  145. data/lib/karafka/pro/routing/features/consumer_groups/adaptive_iterator/topic.rb +90 -0
  146. data/lib/karafka/pro/routing/features/consumer_groups/adaptive_iterator.rb +50 -0
  147. data/lib/karafka/pro/routing/features/{patterns/contracts/consumer_group.rb → consumer_groups/dead_letter_queue/contracts/topic.rb} +25 -30
  148. data/lib/karafka/pro/routing/features/consumer_groups/dead_letter_queue/topic.rb +70 -0
  149. data/lib/karafka/pro/routing/features/consumer_groups/dead_letter_queue.rb +46 -0
  150. data/lib/karafka/pro/routing/features/{direct_assignments → consumer_groups/delaying}/config.rb +6 -4
  151. data/lib/karafka/pro/routing/features/{patterns/contracts/pattern.rb → consumer_groups/delaying/contracts/topic.rb} +13 -16
  152. data/lib/karafka/pro/routing/features/consumer_groups/delaying/topic.rb +85 -0
  153. data/lib/karafka/pro/routing/features/{adaptive_iterator/config.rb → consumer_groups/delaying.rb} +8 -11
  154. data/lib/karafka/pro/routing/features/consumer_groups/direct_assignments/config.rb +46 -0
  155. data/lib/karafka/pro/routing/features/consumer_groups/direct_assignments/contracts/consumer_group.rb +68 -0
  156. data/lib/karafka/pro/routing/features/consumer_groups/direct_assignments/contracts/topic.rb +125 -0
  157. data/lib/karafka/pro/routing/features/consumer_groups/direct_assignments/subscription_group.rb +97 -0
  158. data/lib/karafka/pro/routing/features/consumer_groups/direct_assignments/topic.rb +97 -0
  159. data/lib/karafka/pro/routing/features/consumer_groups/direct_assignments.rb +44 -0
  160. data/lib/karafka/pro/routing/features/consumer_groups/inline_insights/config.rb +51 -0
  161. data/lib/karafka/pro/routing/features/consumer_groups/inline_insights/contracts/topic.rb +58 -0
  162. data/lib/karafka/pro/routing/features/consumer_groups/inline_insights/topic.rb +80 -0
  163. data/lib/karafka/pro/routing/features/consumer_groups/inline_insights.rb +45 -0
  164. data/lib/karafka/pro/routing/features/consumer_groups/long_running_job/config.rb +47 -0
  165. data/lib/karafka/pro/routing/features/{multiplexing/patches/contracts/consumer_group.rb → consumer_groups/long_running_job/contracts/topic.rb} +13 -15
  166. data/lib/karafka/pro/routing/features/consumer_groups/long_running_job/topic.rb +72 -0
  167. data/lib/karafka/pro/routing/features/{long_running_job.rb → consumer_groups/long_running_job.rb} +6 -4
  168. data/lib/karafka/pro/routing/features/consumer_groups/multiplexing/config.rb +58 -0
  169. data/lib/karafka/pro/routing/features/consumer_groups/multiplexing/contracts/routing.rb +83 -0
  170. data/lib/karafka/pro/routing/features/consumer_groups/multiplexing/contracts/topic.rb +148 -0
  171. data/lib/karafka/pro/routing/features/{delaying/contracts/topic.rb → consumer_groups/multiplexing/patches/contracts/consumer_group.rb} +19 -14
  172. data/lib/karafka/pro/routing/features/{multiplexing/subscription_group.rb → consumer_groups/multiplexing/proxy.rb} +17 -23
  173. data/lib/karafka/pro/routing/features/consumer_groups/multiplexing/subscription_group.rb +68 -0
  174. data/lib/karafka/pro/routing/features/{multiplexing → consumer_groups/multiplexing}/subscription_groups_builder.rb +16 -14
  175. data/lib/karafka/pro/routing/features/consumer_groups/multiplexing.rb +85 -0
  176. data/lib/karafka/pro/routing/features/consumer_groups/non_blocking_job/topic.rb +51 -0
  177. data/lib/karafka/pro/routing/features/{non_blocking_job.rb → consumer_groups/non_blocking_job.rb} +15 -13
  178. data/lib/karafka/pro/routing/features/consumer_groups/offset_metadata/config.rb +52 -0
  179. data/lib/karafka/pro/routing/features/consumer_groups/offset_metadata/contracts/topic.rb +59 -0
  180. data/lib/karafka/pro/routing/features/consumer_groups/offset_metadata/topic.rb +93 -0
  181. data/lib/karafka/pro/routing/features/{offset_metadata.rb → consumer_groups/offset_metadata.rb} +16 -14
  182. data/lib/karafka/pro/routing/features/consumer_groups/parallel_segments/builder.rb +74 -0
  183. data/lib/karafka/pro/routing/features/{multiplexing → consumer_groups/parallel_segments}/config.rb +13 -15
  184. data/lib/karafka/pro/routing/features/consumer_groups/parallel_segments/consumer_group.rb +110 -0
  185. data/lib/karafka/pro/routing/features/consumer_groups/parallel_segments/contracts/consumer_group.rb +74 -0
  186. data/lib/karafka/pro/routing/features/{parallel_segments → consumer_groups/parallel_segments}/topic.rb +24 -22
  187. data/lib/karafka/pro/routing/features/consumer_groups/parallel_segments.rb +51 -0
  188. data/lib/karafka/pro/routing/features/{patterns → consumer_groups/patterns}/builder.rb +15 -13
  189. data/lib/karafka/pro/routing/features/{offset_metadata/contracts/topic.rb → consumer_groups/patterns/config.rb} +28 -13
  190. data/lib/karafka/pro/routing/features/consumer_groups/patterns/consumer_group.rb +91 -0
  191. data/lib/karafka/pro/routing/features/consumer_groups/patterns/contracts/consumer_group.rb +83 -0
  192. data/lib/karafka/pro/routing/features/{parallel_segments.rb → consumer_groups/patterns/contracts/pattern.rb} +24 -10
  193. data/lib/karafka/pro/routing/features/consumer_groups/patterns/contracts/topic.rb +58 -0
  194. data/lib/karafka/pro/routing/features/consumer_groups/patterns/detector.rb +98 -0
  195. data/lib/karafka/pro/routing/features/consumer_groups/patterns/pattern.rb +114 -0
  196. data/lib/karafka/pro/routing/features/{recurring_tasks/contracts/topic.rb → consumer_groups/patterns/patterns.rb} +12 -13
  197. data/lib/karafka/pro/routing/features/consumer_groups/patterns/topic.rb +78 -0
  198. data/lib/karafka/pro/routing/features/consumer_groups/patterns/topics.rb +72 -0
  199. data/lib/karafka/pro/routing/features/consumer_groups/patterns.rb +52 -0
  200. data/lib/karafka/pro/routing/features/consumer_groups/periodic_job/config.rb +56 -0
  201. data/lib/karafka/pro/routing/features/{direct_assignments/contracts/consumer_group.rb → consumer_groups/periodic_job/contracts/topic.rb} +17 -22
  202. data/lib/karafka/pro/routing/features/consumer_groups/periodic_job/topic.rb +122 -0
  203. data/lib/karafka/pro/routing/features/consumer_groups/periodic_job.rb +46 -0
  204. data/lib/karafka/pro/routing/features/consumer_groups/recurring_tasks/builder.rb +150 -0
  205. data/lib/karafka/pro/routing/features/{swarm → consumer_groups/recurring_tasks}/config.rb +7 -8
  206. data/lib/karafka/pro/routing/features/{inline_insights → consumer_groups/recurring_tasks}/contracts/topic.rb +14 -13
  207. data/lib/karafka/pro/routing/features/{scheduled_messages → consumer_groups/recurring_tasks}/proxy.rb +6 -4
  208. data/lib/karafka/pro/routing/features/consumer_groups/recurring_tasks/topic.rb +72 -0
  209. data/lib/karafka/pro/routing/features/consumer_groups/recurring_tasks.rb +44 -0
  210. data/lib/karafka/pro/routing/features/consumer_groups/scheduled_messages/builder.rb +154 -0
  211. data/lib/karafka/pro/routing/features/consumer_groups/scheduled_messages/config.rb +47 -0
  212. data/lib/karafka/pro/routing/features/{long_running_job → consumer_groups/scheduled_messages}/contracts/topic.rb +14 -12
  213. data/lib/karafka/pro/routing/features/{delaying/config.rb → consumer_groups/scheduled_messages/proxy.rb} +6 -4
  214. data/lib/karafka/pro/routing/features/consumer_groups/scheduled_messages/topic.rb +72 -0
  215. data/lib/karafka/pro/routing/features/{recurring_tasks/proxy.rb → consumer_groups/scheduled_messages.rb} +3 -4
  216. data/lib/karafka/pro/routing/features/{non_blocking_job/topic.rb → consumer_groups/swarm/config.rb} +9 -8
  217. data/lib/karafka/pro/routing/features/consumer_groups/swarm/contracts/routing.rb +94 -0
  218. data/lib/karafka/pro/routing/features/consumer_groups/swarm/contracts/topic.rb +95 -0
  219. data/lib/karafka/pro/routing/features/consumer_groups/swarm/topic.rb +105 -0
  220. data/lib/karafka/pro/routing/features/consumer_groups/swarm.rb +58 -0
  221. data/lib/karafka/pro/routing/features/consumer_groups/virtual_partitions/config.rb +69 -0
  222. data/lib/karafka/pro/routing/features/{parallel_segments/contracts/consumer_group.rb → consumer_groups/virtual_partitions/contracts/topic.rb} +21 -18
  223. data/lib/karafka/pro/routing/features/consumer_groups/virtual_partitions/topic.rb +101 -0
  224. data/lib/karafka/pro/routing/features/consumer_groups/virtual_partitions.rb +46 -0
  225. data/lib/karafka/pro/routing/features/{scheduled_messages.rb → consumer_groups.rb} +3 -2
  226. data/lib/karafka/pro/routing/features/expiring/topic.rb +4 -4
  227. data/lib/karafka/pro/routing/features/filtering/topic.rb +3 -3
  228. data/lib/karafka/pro/routing/features/pausing/topic.rb +3 -3
  229. data/lib/karafka/pro/routing/features/throttling/topic.rb +4 -4
  230. data/lib/karafka/pro/setup/defaults_injector.rb +70 -0
  231. data/lib/karafka/pro/swarm/liveness_listener.rb +22 -10
  232. data/lib/karafka/processing/consumer_groups/coordinator.rb +221 -0
  233. data/lib/karafka/processing/consumer_groups/coordinators_buffer.rb +69 -0
  234. data/lib/karafka/processing/consumer_groups/executor.rb +220 -0
  235. data/lib/karafka/processing/consumer_groups/executors_buffer.rb +94 -0
  236. data/lib/karafka/processing/consumer_groups/expansions_selector.rb +26 -0
  237. data/lib/karafka/processing/consumer_groups/inline_insights/consumer.rb +47 -0
  238. data/lib/karafka/processing/consumer_groups/inline_insights/listener.rb +23 -0
  239. data/lib/karafka/processing/consumer_groups/inline_insights/tracker.rb +132 -0
  240. data/lib/karafka/processing/consumer_groups/jobs/consume.rb +52 -0
  241. data/lib/karafka/processing/consumer_groups/jobs/eofed.rb +34 -0
  242. data/lib/karafka/processing/consumer_groups/jobs/idle.rb +33 -0
  243. data/lib/karafka/processing/consumer_groups/jobs/revoked.rb +34 -0
  244. data/lib/karafka/processing/consumer_groups/jobs/shutdown.rb +32 -0
  245. data/lib/karafka/processing/consumer_groups/jobs_builder.rb +36 -0
  246. data/lib/karafka/processing/consumer_groups/partitioner.rb +28 -0
  247. data/lib/karafka/processing/consumer_groups/strategies/aj_dlq_mom.rb +48 -0
  248. data/lib/karafka/processing/consumer_groups/strategies/aj_mom.rb +25 -0
  249. data/lib/karafka/processing/consumer_groups/strategies/base.rb +65 -0
  250. data/lib/karafka/processing/consumer_groups/strategies/default.rb +218 -0
  251. data/lib/karafka/processing/consumer_groups/strategies/dlq.rb +157 -0
  252. data/lib/karafka/processing/consumer_groups/strategies/dlq_mom.rb +72 -0
  253. data/lib/karafka/processing/consumer_groups/strategies/mom.rb +33 -0
  254. data/lib/karafka/processing/consumer_groups/strategy_selector.rb +53 -0
  255. data/lib/karafka/processing/coordinator.rb +4 -211
  256. data/lib/karafka/processing/coordinators_buffer.rb +4 -59
  257. data/lib/karafka/processing/jobs_queue.rb +12 -4
  258. data/lib/karafka/processing/partitioner.rb +4 -18
  259. data/lib/karafka/processing/schedulers/default.rb +2 -1
  260. data/lib/karafka/processing/strategy_selector.rb +4 -42
  261. data/lib/karafka/processing/worker.rb +8 -4
  262. data/lib/karafka/processing/workers_pool.rb +158 -0
  263. data/lib/karafka/routing/builder.rb +12 -12
  264. data/lib/karafka/routing/contracts/routing.rb +3 -4
  265. data/lib/karafka/routing/features/base/expander.rb +5 -5
  266. data/lib/karafka/routing/features/consumer_groups/active_job/builder.rb +35 -0
  267. data/lib/karafka/routing/features/consumer_groups/active_job/config.rb +17 -0
  268. data/lib/karafka/routing/features/consumer_groups/active_job/contracts/topic.rb +44 -0
  269. data/lib/karafka/routing/features/consumer_groups/active_job/proxy.rb +16 -0
  270. data/lib/karafka/routing/features/consumer_groups/active_job/topic.rb +50 -0
  271. data/lib/karafka/routing/features/consumer_groups/active_job.rb +15 -0
  272. data/lib/karafka/routing/features/consumer_groups/dead_letter_queue/config.rb +39 -0
  273. data/lib/karafka/routing/features/consumer_groups/dead_letter_queue/contracts/topic.rb +58 -0
  274. data/lib/karafka/routing/features/consumer_groups/dead_letter_queue/topic.rb +76 -0
  275. data/lib/karafka/routing/features/consumer_groups/dead_letter_queue.rb +18 -0
  276. data/lib/karafka/routing/features/consumer_groups/eofed/config.rb +17 -0
  277. data/lib/karafka/routing/features/consumer_groups/eofed/contracts/topic.rb +39 -0
  278. data/lib/karafka/routing/features/consumer_groups/eofed/topic.rb +42 -0
  279. data/lib/karafka/routing/features/consumer_groups/eofed.rb +16 -0
  280. data/lib/karafka/routing/features/consumer_groups/inline_insights/config.rb +17 -0
  281. data/lib/karafka/routing/features/consumer_groups/inline_insights/contracts/topic.rb +27 -0
  282. data/lib/karafka/routing/features/consumer_groups/inline_insights/topic.rb +42 -0
  283. data/lib/karafka/routing/features/consumer_groups/inline_insights.rb +42 -0
  284. data/lib/karafka/routing/features/consumer_groups/manual_offset_management/config.rb +17 -0
  285. data/lib/karafka/routing/features/consumer_groups/manual_offset_management/contracts/topic.rb +27 -0
  286. data/lib/karafka/routing/features/consumer_groups/manual_offset_management/topic.rb +46 -0
  287. data/lib/karafka/routing/features/consumer_groups/manual_offset_management.rb +20 -0
  288. data/lib/karafka/routing/features/consumer_groups.rb +12 -0
  289. data/lib/karafka/routing/features/declaratives/contracts/topic.rb +4 -19
  290. data/lib/karafka/routing/features/declaratives/topic.rb +30 -14
  291. data/lib/karafka/routing/features/deserializers/topic.rb +3 -3
  292. data/lib/karafka/routing/router.rb +2 -2
  293. data/lib/karafka/routing/subscription_group.rb +18 -9
  294. data/lib/karafka/routing/topic.rb +25 -11
  295. data/lib/karafka/runner.rb +17 -17
  296. data/lib/karafka/server.rb +28 -6
  297. data/lib/karafka/setup/attributes_map.rb +2 -0
  298. data/lib/karafka/setup/config.rb +64 -15
  299. data/lib/karafka/setup/config_proxy.rb +1 -2
  300. data/lib/karafka/setup/contracts/config.rb +28 -8
  301. data/lib/karafka/setup/defaults_injector.rb +10 -0
  302. data/lib/karafka/status.rb +1 -2
  303. data/lib/karafka/swarm/liveness_listener.rb +7 -0
  304. data/lib/karafka/swarm/manager.rb +7 -7
  305. data/lib/karafka/swarm/node.rb +8 -0
  306. data/lib/karafka/swarm/supervisor.rb +9 -1
  307. data/lib/karafka/templates/karafka.rb.erb +11 -5
  308. data/lib/karafka/version.rb +1 -1
  309. metadata +237 -224
  310. data/lib/karafka/connection/rebalance_manager.rb +0 -116
  311. data/lib/karafka/instrumentation/callbacks/error.rb +0 -52
  312. data/lib/karafka/instrumentation/callbacks/rebalance.rb +0 -84
  313. data/lib/karafka/instrumentation/callbacks/statistics.rb +0 -55
  314. data/lib/karafka/pro/processing/adaptive_iterator/consumer.rb +0 -79
  315. data/lib/karafka/pro/processing/adaptive_iterator/tracker.rb +0 -92
  316. data/lib/karafka/pro/processing/collapser.rb +0 -79
  317. data/lib/karafka/pro/processing/coordinator.rb +0 -197
  318. data/lib/karafka/pro/processing/coordinators/errors_tracker.rb +0 -119
  319. data/lib/karafka/pro/processing/coordinators/filters_applier.rb +0 -152
  320. data/lib/karafka/pro/processing/coordinators/virtual_offset_manager.rb +0 -207
  321. data/lib/karafka/pro/processing/expansions_selector.rb +0 -52
  322. data/lib/karafka/pro/processing/filters/delayer.rb +0 -87
  323. data/lib/karafka/pro/processing/filters/inline_insights_delayer.rb +0 -95
  324. data/lib/karafka/pro/processing/filters/throttler.rb +0 -101
  325. data/lib/karafka/pro/processing/filters/virtual_limiter.rb +0 -74
  326. data/lib/karafka/pro/processing/jobs/eofed_non_blocking.rb +0 -51
  327. data/lib/karafka/pro/processing/jobs_builder.rb +0 -90
  328. data/lib/karafka/pro/processing/offset_metadata/consumer.rb +0 -61
  329. data/lib/karafka/pro/processing/offset_metadata/fetcher.rb +0 -149
  330. data/lib/karafka/pro/processing/offset_metadata/listener.rb +0 -63
  331. data/lib/karafka/pro/processing/parallel_segments/filters/base.rb +0 -98
  332. data/lib/karafka/pro/processing/parallel_segments/filters/default.rb +0 -110
  333. data/lib/karafka/pro/processing/parallel_segments/filters/mom.rb +0 -91
  334. data/lib/karafka/pro/processing/periodic_job/consumer.rb +0 -85
  335. data/lib/karafka/pro/processing/piping/consumer.rb +0 -149
  336. data/lib/karafka/pro/processing/strategies/aj/dlq_ftr_lrj_mom_vp.rb +0 -94
  337. data/lib/karafka/pro/processing/strategies/aj/dlq_ftr_mom.rb +0 -87
  338. data/lib/karafka/pro/processing/strategies/aj/dlq_ftr_mom_vp.rb +0 -85
  339. data/lib/karafka/pro/processing/strategies/aj/dlq_lrj_mom.rb +0 -81
  340. data/lib/karafka/pro/processing/strategies/aj/dlq_lrj_mom_vp.rb +0 -85
  341. data/lib/karafka/pro/processing/strategies/aj/dlq_mom.rb +0 -79
  342. data/lib/karafka/pro/processing/strategies/aj/dlq_mom_vp.rb +0 -84
  343. data/lib/karafka/pro/processing/strategies/aj/ftr_lrj_mom_vp.rb +0 -86
  344. data/lib/karafka/pro/processing/strategies/aj/lrj_mom.rb +0 -54
  345. data/lib/karafka/pro/processing/strategies/aj/lrj_mom_vp.rb +0 -101
  346. data/lib/karafka/pro/processing/strategies/base.rb +0 -43
  347. data/lib/karafka/pro/processing/strategies/default.rb +0 -416
  348. data/lib/karafka/pro/processing/strategies/dlq/default.rb +0 -280
  349. data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj.rb +0 -90
  350. data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj_mom.rb +0 -92
  351. data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj_mom_vp.rb +0 -60
  352. data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj_vp.rb +0 -58
  353. data/lib/karafka/pro/processing/strategies/dlq/ftr_mom.rb +0 -92
  354. data/lib/karafka/pro/processing/strategies/dlq/ftr_mom_vp.rb +0 -58
  355. data/lib/karafka/pro/processing/strategies/dlq/ftr_vp.rb +0 -57
  356. data/lib/karafka/pro/processing/strategies/dlq/lrj_mom.rb +0 -95
  357. data/lib/karafka/pro/processing/strategies/dlq/lrj_vp.rb +0 -56
  358. data/lib/karafka/pro/processing/strategies/dlq/mom.rb +0 -91
  359. data/lib/karafka/pro/processing/strategies/dlq/mom_vp.rb +0 -54
  360. data/lib/karafka/pro/processing/strategies/dlq/vp.rb +0 -57
  361. data/lib/karafka/pro/processing/strategies/ftr/default.rb +0 -141
  362. data/lib/karafka/pro/processing/strategies/ftr/vp.rb +0 -57
  363. data/lib/karafka/pro/processing/strategies/lrj/default.rb +0 -114
  364. data/lib/karafka/pro/processing/strategies/lrj/ftr.rb +0 -89
  365. data/lib/karafka/pro/processing/strategies/lrj/ftr_mom.rb +0 -87
  366. data/lib/karafka/pro/processing/strategies/lrj/ftr_mom_vp.rb +0 -57
  367. data/lib/karafka/pro/processing/strategies/lrj/ftr_vp.rb +0 -56
  368. data/lib/karafka/pro/processing/strategies/lrj/mom.rb +0 -96
  369. data/lib/karafka/pro/processing/strategies/mom/ftr_vp.rb +0 -54
  370. data/lib/karafka/pro/processing/strategies/vp/default.rb +0 -192
  371. data/lib/karafka/pro/processing/strategies.rb +0 -39
  372. data/lib/karafka/pro/processing/strategy_selector.rb +0 -102
  373. data/lib/karafka/pro/processing/subscription_groups_coordinator.rb +0 -68
  374. data/lib/karafka/pro/processing/virtual_partitions/distributors/balanced.rb +0 -77
  375. data/lib/karafka/pro/routing/features/active_job.rb +0 -43
  376. data/lib/karafka/pro/routing/features/adaptive_iterator/contracts/topic.rb +0 -89
  377. data/lib/karafka/pro/routing/features/adaptive_iterator/topic.rb +0 -88
  378. data/lib/karafka/pro/routing/features/adaptive_iterator.rb +0 -48
  379. data/lib/karafka/pro/routing/features/dead_letter_queue/contracts/topic.rb +0 -74
  380. data/lib/karafka/pro/routing/features/dead_letter_queue/topic.rb +0 -68
  381. data/lib/karafka/pro/routing/features/dead_letter_queue.rb +0 -44
  382. data/lib/karafka/pro/routing/features/delaying/topic.rb +0 -83
  383. data/lib/karafka/pro/routing/features/delaying.rb +0 -46
  384. data/lib/karafka/pro/routing/features/direct_assignments/contracts/topic.rb +0 -123
  385. data/lib/karafka/pro/routing/features/direct_assignments/subscription_group.rb +0 -95
  386. data/lib/karafka/pro/routing/features/direct_assignments/topic.rb +0 -95
  387. data/lib/karafka/pro/routing/features/direct_assignments.rb +0 -42
  388. data/lib/karafka/pro/routing/features/inline_insights/topic.rb +0 -78
  389. data/lib/karafka/pro/routing/features/inline_insights.rb +0 -43
  390. data/lib/karafka/pro/routing/features/long_running_job/config.rb +0 -45
  391. data/lib/karafka/pro/routing/features/long_running_job/topic.rb +0 -70
  392. data/lib/karafka/pro/routing/features/multiplexing/contracts/routing.rb +0 -81
  393. data/lib/karafka/pro/routing/features/multiplexing/contracts/topic.rb +0 -146
  394. data/lib/karafka/pro/routing/features/multiplexing/proxy.rb +0 -58
  395. data/lib/karafka/pro/routing/features/multiplexing.rb +0 -83
  396. data/lib/karafka/pro/routing/features/offset_metadata/config.rb +0 -50
  397. data/lib/karafka/pro/routing/features/offset_metadata/topic.rb +0 -91
  398. data/lib/karafka/pro/routing/features/parallel_segments/builder.rb +0 -72
  399. data/lib/karafka/pro/routing/features/parallel_segments/config.rb +0 -52
  400. data/lib/karafka/pro/routing/features/parallel_segments/consumer_group.rb +0 -108
  401. data/lib/karafka/pro/routing/features/patterns/config.rb +0 -71
  402. data/lib/karafka/pro/routing/features/patterns/consumer_group.rb +0 -89
  403. data/lib/karafka/pro/routing/features/patterns/contracts/topic.rb +0 -56
  404. data/lib/karafka/pro/routing/features/patterns/detector.rb +0 -96
  405. data/lib/karafka/pro/routing/features/patterns/pattern.rb +0 -112
  406. data/lib/karafka/pro/routing/features/patterns/topic.rb +0 -76
  407. data/lib/karafka/pro/routing/features/patterns/topics.rb +0 -70
  408. data/lib/karafka/pro/routing/features/patterns.rb +0 -50
  409. data/lib/karafka/pro/routing/features/periodic_job/config.rb +0 -54
  410. data/lib/karafka/pro/routing/features/periodic_job/contracts/topic.rb +0 -59
  411. data/lib/karafka/pro/routing/features/periodic_job/topic.rb +0 -120
  412. data/lib/karafka/pro/routing/features/periodic_job.rb +0 -44
  413. data/lib/karafka/pro/routing/features/recurring_tasks/builder.rb +0 -148
  414. data/lib/karafka/pro/routing/features/recurring_tasks/config.rb +0 -45
  415. data/lib/karafka/pro/routing/features/recurring_tasks/topic.rb +0 -70
  416. data/lib/karafka/pro/routing/features/recurring_tasks.rb +0 -42
  417. data/lib/karafka/pro/routing/features/scheduled_messages/builder.rb +0 -152
  418. data/lib/karafka/pro/routing/features/scheduled_messages/config.rb +0 -45
  419. data/lib/karafka/pro/routing/features/scheduled_messages/contracts/topic.rb +0 -55
  420. data/lib/karafka/pro/routing/features/scheduled_messages/topic.rb +0 -70
  421. data/lib/karafka/pro/routing/features/swarm/contracts/routing.rb +0 -92
  422. data/lib/karafka/pro/routing/features/swarm/contracts/topic.rb +0 -93
  423. data/lib/karafka/pro/routing/features/swarm/topic.rb +0 -103
  424. data/lib/karafka/pro/routing/features/swarm.rb +0 -56
  425. data/lib/karafka/pro/routing/features/virtual_partitions/config.rb +0 -67
  426. data/lib/karafka/pro/routing/features/virtual_partitions/contracts/topic.rb +0 -73
  427. data/lib/karafka/pro/routing/features/virtual_partitions/topic.rb +0 -99
  428. data/lib/karafka/pro/routing/features/virtual_partitions.rb +0 -44
  429. data/lib/karafka/processing/executor.rb +0 -216
  430. data/lib/karafka/processing/executors_buffer.rb +0 -90
  431. data/lib/karafka/processing/expansions_selector.rb +0 -22
  432. data/lib/karafka/processing/inline_insights/consumer.rb +0 -43
  433. data/lib/karafka/processing/inline_insights/listener.rb +0 -19
  434. data/lib/karafka/processing/inline_insights/tracker.rb +0 -129
  435. data/lib/karafka/processing/jobs/consume.rb +0 -47
  436. data/lib/karafka/processing/jobs/eofed.rb +0 -29
  437. data/lib/karafka/processing/jobs/idle.rb +0 -31
  438. data/lib/karafka/processing/jobs/revoked.rb +0 -29
  439. data/lib/karafka/processing/jobs/shutdown.rb +0 -30
  440. data/lib/karafka/processing/jobs_builder.rb +0 -34
  441. data/lib/karafka/processing/strategies/aj_dlq_mom.rb +0 -44
  442. data/lib/karafka/processing/strategies/aj_mom.rb +0 -21
  443. data/lib/karafka/processing/strategies/base.rb +0 -61
  444. data/lib/karafka/processing/strategies/default.rb +0 -214
  445. data/lib/karafka/processing/strategies/dlq.rb +0 -153
  446. data/lib/karafka/processing/strategies/dlq_mom.rb +0 -68
  447. data/lib/karafka/processing/strategies/mom.rb +0 -29
  448. data/lib/karafka/processing/workers_batch.rb +0 -29
  449. data/lib/karafka/routing/features/active_job/builder.rb +0 -33
  450. data/lib/karafka/routing/features/active_job/config.rb +0 -15
  451. data/lib/karafka/routing/features/active_job/contracts/topic.rb +0 -42
  452. data/lib/karafka/routing/features/active_job/proxy.rb +0 -14
  453. data/lib/karafka/routing/features/active_job/topic.rb +0 -48
  454. data/lib/karafka/routing/features/active_job.rb +0 -13
  455. data/lib/karafka/routing/features/dead_letter_queue/config.rb +0 -37
  456. data/lib/karafka/routing/features/dead_letter_queue/contracts/topic.rb +0 -56
  457. data/lib/karafka/routing/features/dead_letter_queue/topic.rb +0 -74
  458. data/lib/karafka/routing/features/dead_letter_queue.rb +0 -16
  459. data/lib/karafka/routing/features/declaratives/config.rb +0 -18
  460. data/lib/karafka/routing/features/eofed/config.rb +0 -15
  461. data/lib/karafka/routing/features/eofed/contracts/topic.rb +0 -37
  462. data/lib/karafka/routing/features/eofed/topic.rb +0 -40
  463. data/lib/karafka/routing/features/eofed.rb +0 -14
  464. data/lib/karafka/routing/features/inline_insights/config.rb +0 -15
  465. data/lib/karafka/routing/features/inline_insights/contracts/topic.rb +0 -25
  466. data/lib/karafka/routing/features/inline_insights/topic.rb +0 -40
  467. data/lib/karafka/routing/features/inline_insights.rb +0 -40
  468. data/lib/karafka/routing/features/manual_offset_management/config.rb +0 -15
  469. data/lib/karafka/routing/features/manual_offset_management/contracts/topic.rb +0 -25
  470. data/lib/karafka/routing/features/manual_offset_management/topic.rb +0 -44
  471. data/lib/karafka/routing/features/manual_offset_management.rb +0 -18
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Processing
5
+ # Consumer-group-specific processing components (driven by rebalance callbacks and partition
6
+ # ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
7
+ module ConsumerGroups
8
+ # Coordinators builder used to build coordinators per topic partition
9
+ #
10
+ # It provides direct pauses access for revocation
11
+ #
12
+ # @note This buffer operates only from the listener loop, thus we do not have to make it
13
+ # thread-safe.
14
+ class CoordinatorsBuffer
15
+ include Helpers::ConfigImporter.new(
16
+ coordinator_class: %i[internal processing consumer_groups coordinator_class]
17
+ )
18
+
19
+ # @param topics [Karafka::Routing::Topics]
20
+ def initialize(topics)
21
+ @pauses_manager = Connection::PausesManager.new
22
+ @coordinators = Hash.new { |h, k| h[k] = {} }
23
+ @topics = topics
24
+ end
25
+
26
+ # @param topic_name [String] topic name
27
+ # @param partition [Integer] partition number
28
+ # @return [Karafka::Processing::ConsumerGroups::Coordinator] found or created coordinator
29
+ def find_or_create(topic_name, partition)
30
+ @coordinators[topic_name][partition] ||= begin
31
+ routing_topic = @topics.find(topic_name)
32
+
33
+ coordinator_class.new(
34
+ routing_topic,
35
+ partition,
36
+ @pauses_manager.fetch(routing_topic, partition)
37
+ )
38
+ end
39
+ end
40
+
41
+ # Resumes processing of partitions for which pause time has ended.
42
+ # @yieldparam [String] topic name
43
+ # @yieldparam [Integer] partition number
44
+ def resume(&)
45
+ @pauses_manager.resume(&)
46
+ end
47
+
48
+ # @param topic_name [String] topic name
49
+ # @param partition [Integer] partition number
50
+ def revoke(topic_name, partition)
51
+ return unless @coordinators[topic_name].key?(partition)
52
+
53
+ # The fact that we delete here does not change the fact that the executor still holds the
54
+ # reference to this coordinator. We delete it here, as we will no longer process any
55
+ # new stuff with it and we may need a new coordinator if we regain this partition, but the
56
+ # coordinator may still be in use
57
+ @coordinators[topic_name].delete(partition).revoke
58
+ end
59
+
60
+ # Clears coordinators and re-created the pauses manager
61
+ # This should be used only for critical errors recovery
62
+ def reset
63
+ @pauses_manager = Connection::PausesManager.new
64
+ @coordinators.clear
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ # Namespace that encapsulates all the logic related to processing data.
5
+ module Processing
6
+ # Consumer-group-specific processing components (driven by rebalance callbacks and partition
7
+ # ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
8
+ module ConsumerGroups
9
+ # Executors:
10
+ # - run consumers code (for `#call`) or run given preparation / teardown operations when needed
11
+ # from separate threads.
12
+ # - they re-create consumer instances in case of partitions that were revoked and assigned
13
+ # back.
14
+ #
15
+ # @note Executors are not removed after partition is revoked. They are not that big and will
16
+ # be re-used in case of a re-claim
17
+ #
18
+ # @note Since given consumer can run various operations, executor manages that and its
19
+ # lifecycle. There are following types of operations with appropriate before/after, etc:
20
+ #
21
+ # - consume - primary operation related to running user consumption code
22
+ # - idle - cleanup job that runs on idle runs where no messages would be passed to the end
23
+ # user. This is used for complex flows with filters, etc
24
+ # - revoked - runs after the partition was revoked
25
+ # - shutdown - runs when process is going to shutdown
26
+ class Executor
27
+ extend Forwardable
28
+ include Helpers::ConfigImporter.new(
29
+ strategy_selector: %i[internal processing consumer_groups strategy_selector],
30
+ expansions_selector: %i[internal processing consumer_groups expansions_selector]
31
+ )
32
+
33
+ def_delegators :@coordinator, :topic, :partition
34
+
35
+ # @return [String] unique id that we use to ensure, that we use for state tracking
36
+ attr_reader :id
37
+
38
+ # @return [String] subscription group id to which a given executor belongs
39
+ attr_reader :group_id
40
+
41
+ # @return [Karafka::Messages::Messages] messages batch
42
+ attr_reader :messages
43
+
44
+ # @return [Karafka::Processing::ConsumerGroups::Coordinator] coordinator for this executor
45
+ attr_reader :coordinator
46
+
47
+ # @param group_id [String] id of the subscription group to which the executor belongs
48
+ # @param client [Karafka::Connection::Client] kafka client
49
+ # @param coordinator [Karafka::Processing::ConsumerGroups::Coordinator]
50
+ def initialize(group_id, client, coordinator)
51
+ @id = SecureRandom.hex(6)
52
+ @group_id = group_id
53
+ @client = client
54
+ @coordinator = coordinator
55
+ end
56
+
57
+ # Allows us to prepare the consumer in the listener thread prior to the job being send to
58
+ # be scheduled. It also allows to run some code that is time sensitive and cannot wait in the
59
+ # queue as it could cause starvation.
60
+ #
61
+ # @param messages [Array<Karafka::Messages::Message>]
62
+ def before_schedule_consume(messages)
63
+ # Recreate consumer with each batch if persistence is not enabled
64
+ # We reload the consumers with each batch instead of relying on some external signals
65
+ # when needed for consistency. That way devs may have it on or off and not in this
66
+ # middle state, where re-creation of a consumer instance would occur only sometimes
67
+ @consumer = nil unless topic.consumer_persistence
68
+
69
+ # First we build messages batch...
70
+ consumer.messages = Messages::Builders::Messages.call(
71
+ messages,
72
+ topic,
73
+ partition,
74
+ # the moment we've received the batch or actually the moment we've enqueued it,
75
+ # but good enough
76
+ Time.now
77
+ )
78
+
79
+ consumer.on_before_schedule_consume
80
+ end
81
+
82
+ # Runs setup and warm-up code in the worker prior to running the consumption
83
+ def before_consume
84
+ consumer.on_before_consume
85
+ end
86
+
87
+ # Runs the wrap/around execution context appropriate for a given action
88
+ # @param action [Symbol] action execution wrapped with our block
89
+ def wrap(action, &)
90
+ consumer.on_wrap(action, &)
91
+ end
92
+
93
+ # Runs consumer data processing against given batch and handles failures and errors.
94
+ def consume
95
+ # We run the consumer client logic...
96
+ consumer.on_consume
97
+ end
98
+
99
+ # Runs consumer after consumption code
100
+ def after_consume
101
+ consumer.on_after_consume
102
+ end
103
+
104
+ # Runs the code needed before idle work is scheduled
105
+ def before_schedule_idle
106
+ consumer.on_before_schedule_idle
107
+ end
108
+
109
+ # Runs consumer idle operations
110
+ # This may include house-keeping or other state management changes that can occur but that
111
+ # not mean there are any new messages available for the end user to process
112
+ def idle
113
+ consumer.on_idle
114
+ end
115
+
116
+ # Runs the code needed before eofed work is scheduled
117
+ def before_schedule_eofed
118
+ consumer.on_before_schedule_eofed
119
+ end
120
+
121
+ # Runs consumed eofed operation.
122
+ # This may run even when there were no messages received prior. This will however not
123
+ # run when eof is received together with messages as in such case `#consume` will run
124
+ def eofed
125
+ consumer.on_eofed
126
+ end
127
+
128
+ # Runs code needed before revoked job is scheduled
129
+ def before_schedule_revoked
130
+ consumer.on_before_schedule_revoked if @consumer
131
+ end
132
+
133
+ # Runs the controller `#revoked` method that should be triggered when a given consumer is
134
+ # no longer needed due to partitions reassignment.
135
+ #
136
+ # @note Clearing the consumer will ensure, that if we get the partition back, it will be
137
+ # handled with a consumer with a clean state.
138
+ #
139
+ # @note We run it only when consumer was present, because presence indicates, that at least
140
+ # a single message has been consumed.
141
+ #
142
+ # @note We do not reset the consumer but we indicate need for recreation instead, because
143
+ # after the revocation, there still may be `#after_consume` running that needs a given
144
+ # consumer instance.
145
+ def revoked
146
+ consumer.on_revoked if @consumer
147
+ end
148
+
149
+ # Runs code needed before shutdown job is scheduled
150
+ def before_schedule_shutdown
151
+ consumer.on_before_schedule_shutdown if @consumer
152
+ end
153
+
154
+ # Runs the controller `#shutdown` method that should be triggered when a given consumer is
155
+ # no longer needed as we're closing the process.
156
+ #
157
+ # @note While we do not need to clear the consumer here, it's a good habit to clean after
158
+ # work is done.
159
+ def shutdown
160
+ # There is a case, where the consumer no longer exists because it was revoked, in case like
161
+ # that we do not build a new instance and shutdown should not be triggered.
162
+ consumer.on_shutdown if @consumer
163
+ end
164
+
165
+ private
166
+
167
+ # @return [Object] cached consumer instance
168
+ def consumer
169
+ @consumer ||= begin
170
+ topic = @coordinator.topic
171
+
172
+ strategy = strategy_selector.find(topic)
173
+
174
+ consumer = topic.consumer_class.new
175
+ # We use singleton class as the same consumer class may be used to process different
176
+ # topics with different settings
177
+ consumer.singleton_class.include(strategy)
178
+
179
+ # Specific features may expand consumer API beyond the injected strategy. The difference
180
+ # here is that strategy impacts the flow of states while extra APIs just provide some
181
+ # extra methods with informations, etc but do no deviate the flow behavior
182
+ expansions = expansions_selector.find(topic)
183
+ expansions.each { |expansion| consumer.singleton_class.include(expansion) }
184
+
185
+ consumer.client = @client
186
+ consumer.coordinator = @coordinator
187
+ # We assign producer only when not available already. It may already be available if
188
+ # user redefined the `#producer` method for example. This can be useful for example when
189
+ # having a multi-cluster setup and using a totally custom producer
190
+ consumer.producer ||= Karafka::App.producer
191
+ # Since we have some message-less flows (idle, etc), we initialize consumer with empty
192
+ # messages set. In production we have persistent consumers, so this is not a performance
193
+ # overhead as this will happen only once per consumer lifetime
194
+ consumer.messages = empty_messages
195
+
196
+ # Run the post-initialization hook for users that need to run some actions when consumer
197
+ # is built and ready (all basic state and info).
198
+ # Users should **not** overwrite the `#initialize` because it won't have all the needed
199
+ # data assigned yet.
200
+ consumer.on_initialized
201
+
202
+ consumer
203
+ end
204
+ end
205
+
206
+ # Initializes the messages set in case given operation would happen before any processing
207
+ # This prevents us from having no messages object at all as the messages object and
208
+ # its metadata may be used for statistics
209
+ def empty_messages
210
+ Messages::Builders::Messages.call(
211
+ [],
212
+ topic,
213
+ partition,
214
+ Time.now
215
+ )
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Processing
5
+ # Consumer-group-specific processing components (driven by rebalance callbacks and partition
6
+ # ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
7
+ module ConsumerGroups
8
+ # Buffer for executors of a given subscription group. It wraps around the concept of building
9
+ # and caching them, so we can re-use them instead of creating new each time.
10
+ class ExecutorsBuffer
11
+ include Helpers::ConfigImporter.new(
12
+ executor_class: %i[internal processing consumer_groups executor_class]
13
+ )
14
+
15
+ # @param client [Connection::Client]
16
+ # @param subscription_group [Routing::SubscriptionGroup]
17
+ # @return [ExecutorsBuffer]
18
+ def initialize(client, subscription_group)
19
+ @subscription_group = subscription_group
20
+ @client = client
21
+ # We need two layers here to keep track of topics, partitions and processing groups
22
+ @buffer = Hash.new { |h, k| h[k] = Hash.new { |h2, k2| h2[k2] = {} } }
23
+ end
24
+
25
+ # Finds or creates an executor based on the provided details
26
+ #
27
+ # @param topic [String] topic name
28
+ # @param partition [Integer] partition number
29
+ # @param parallel_key [String] parallel group key
30
+ # @param coordinator [Karafka::Processing::ConsumerGroups::Coordinator]
31
+ # @return [Executor, Pro::Processing::ConsumerGroups::Executor] consumer executor
32
+ def find_or_create(topic, partition, parallel_key, coordinator)
33
+ @buffer[topic][partition][parallel_key] ||= executor_class.new(
34
+ @subscription_group.id,
35
+ @client,
36
+ coordinator
37
+ )
38
+ end
39
+
40
+ # Finds all existing executors for given topic partition or creates one for it
41
+ # @param topic [String] topic name
42
+ # @param partition [Integer] partition number
43
+ # @param coordinator [Karafka::Processing::ConsumerGroups::Coordinator]
44
+ # @return [Array<Executor, Pro::Processing::ConsumerGroups::Executor>]
45
+ def find_all_or_create(topic, partition, coordinator)
46
+ existing = find_all(topic, partition)
47
+
48
+ return existing unless existing.empty?
49
+
50
+ [find_or_create(topic, partition, 0, coordinator)]
51
+ end
52
+
53
+ # Revokes executors of a given topic partition, so they won't be used anymore for incoming
54
+ # messages
55
+ #
56
+ # @param topic [String] topic name
57
+ # @param partition [Integer] partition number
58
+ def revoke(topic, partition)
59
+ @buffer[topic][partition].clear
60
+ end
61
+
62
+ # Finds all the executors available for a given topic partition
63
+ #
64
+ # @param topic [String] topic name
65
+ # @param partition [Integer] partition number
66
+ # @return [Array<Executor, Pro::Processing::ConsumerGroups::Executor>] executors in use for this
67
+ # topic + partition
68
+ def find_all(topic, partition)
69
+ @buffer[topic][partition].values
70
+ end
71
+
72
+ # Iterates over all available executors and yields them together with topic and partition
73
+ # info
74
+ # @yieldparam [Routing::Topic] karafka routing topic object
75
+ # @yieldparam [Integer] partition number
76
+ # @yieldparam [Executor, Pro::Processing::ConsumerGroups::Executor] given executor
77
+ def each
78
+ @buffer.each_value do |partitions|
79
+ partitions.each_value do |executors|
80
+ executors.each_value do |executor|
81
+ yield(executor)
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ # Clears the executors buffer. Useful for critical errors recovery.
88
+ def clear
89
+ @buffer.clear
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Processing
5
+ # Consumer-group-specific processing components (driven by rebalance callbacks and partition
6
+ # ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
7
+ module ConsumerGroups
8
+ # Selector of appropriate topic setup based features enhancements.
9
+ #
10
+ # Those expansions to the consumer API are NOT about the flow of processing. For this we have
11
+ # strategies. Those are suppose to provide certain extra APIs that user can use to get some
12
+ # extra non-flow related functionalities.
13
+ class ExpansionsSelector
14
+ # @param topic [Karafka::Routing::Topic] topic with settings based on which we find
15
+ # expansions
16
+ # @return [Array<Module>] modules with proper expansions we're suppose to use to enhance the
17
+ # consumer
18
+ def find(topic)
19
+ expansions = []
20
+ expansions << Processing::ConsumerGroups::InlineInsights::Consumer if topic.inline_insights?
21
+ expansions
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Processing
5
+ # Consumer-group-specific processing components (driven by rebalance callbacks and partition
6
+ # ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
7
+ module ConsumerGroups
8
+ # Namespace of the Inline Insights feature "non routing" related components
9
+ #
10
+ # @note We use both `#insights` because it is the feature name but also `#statistics` to make
11
+ # it consistent with the fact that we publish and operate on statistics. User can pick
12
+ # whichever name they prefer.
13
+ module InlineInsights
14
+ # Module that adds extra methods to the consumer that allow us to fetch the insights
15
+ module Consumer
16
+ # @return [Hash] empty hash or hash with given partition insights if already present
17
+ # @note We cache insights on the consumer, as in some scenarios we may no longer have them
18
+ # inside the Tracker, for example under involuntary revocation, incoming statistics may
19
+ # no longer have lost partition insights. Since we want to be consistent during single
20
+ # batch operations, we want to ensure, that if we have insights they are available
21
+ # throughout the whole processing.
22
+ def insights
23
+ insights = Tracker.find(topic, partition)
24
+
25
+ # If we no longer have new insights but we still have them locally, we can use them
26
+ return @insights if @insights && insights.empty?
27
+ # If insights are still the same, we can use them
28
+ return @insights if @insights.equal?(insights)
29
+
30
+ # If we've received new insights that are not empty, we can cache them
31
+ @insights = insights
32
+ end
33
+
34
+ # @return [Boolean] true if there are insights to work with, otherwise false
35
+ def insights?
36
+ !insights.empty?
37
+ end
38
+
39
+ alias_method :statistics, :insights
40
+ alias_method :statistics?, :insights?
41
+ alias_method :inline_insights, :insights
42
+ alias_method :inline_insights?, :insights?
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Processing
5
+ # Consumer-group-specific processing components (driven by rebalance callbacks and partition
6
+ # ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
7
+ module ConsumerGroups
8
+ module InlineInsights
9
+ # Listener that adds statistics to our inline tracker
10
+ class Listener
11
+ # Adds statistics to the tracker
12
+ # @param event [Karafka::Core::Monitoring::Event] event with statistics
13
+ def on_statistics_emitted(event)
14
+ Tracker.add(
15
+ event[:group_id],
16
+ event[:statistics]
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Processing
5
+ # Consumer-group-specific processing components (driven by rebalance callbacks and partition
6
+ # ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
7
+ module ConsumerGroups
8
+ module InlineInsights
9
+ # Object used to track statistics coming from librdkafka in a way that can be accessible by
10
+ # the consumers
11
+ #
12
+ # We use a single tracker because we do not need state management here as our consumer groups
13
+ # clients identified by statistics name value are unique. On top of that, having a per
14
+ # process one that is a singleton allows us to use tracker easily also from other places like
15
+ # filtering API etc.
16
+ #
17
+ # @note We include cache of 5 minutes for revoked partitions to compensate for cases where
18
+ # when using LRJ a lost partition data would not be present anymore, however we would still
19
+ # be in the processing phase. Since those metrics are published with each `poll`, regular
20
+ # processing is not a subject of this issue. For LRJ we keep the reference. The only case
21
+ # where this could be switched midway is when LRJ is running for an extended period of time
22
+ # after the involuntary revocation. Having a time based cache instead of tracking
23
+ # simplifies the design as we do not have to deal with state tracking, especially since
24
+ # we would have to track also operations running in a revoked state.
25
+ #
26
+ # @note This tracker keeps in memory data about all topics and partitions that it encounters
27
+ # because in case of routing patterns, we may start getting statistics prior to registering
28
+ # given topic via dynamic routing expansions. In such case we would not have insights
29
+ # where they were actually available for us to use.
30
+ #
31
+ # @note Memory usage is negligible as long as we can evict expired data. Single metrics set
32
+ # for a single partition contains around 4KB of data. This means, that in case of an
33
+ # assignment of 1000 partitions, we use around 4MB of space for tracking those metrics.
34
+ class Tracker
35
+ include Singleton
36
+ include Karafka::Core::Helpers::Time
37
+
38
+ # Empty hash we want to return in any case where we could not locate appropriate topic
39
+ # partition statistics.
40
+ EMPTY_HASH = {}.freeze
41
+
42
+ # Empty array to save on memory allocations.
43
+ EMPTY_ARRAY = [].freeze
44
+
45
+ # 5 minutes of cache. We cache last result per consumer group topic partition so we are
46
+ # not affected by involuntary rebalances during LRJ execution.
47
+ TTL = 5 * 60 * 1_000
48
+
49
+ private_constant :EMPTY_HASH, :EMPTY_ARRAY, :TTL
50
+
51
+ class << self
52
+ extend Forwardable
53
+
54
+ def_delegators :instance, :find, :add, :exists?, :clear
55
+ end
56
+
57
+ # Initializes the tracker with empty accumulator
58
+ def initialize
59
+ @accu = {}
60
+ @mutex = Mutex.new
61
+ end
62
+
63
+ # Adds each partition statistics into internal accumulator. Single statistics set may
64
+ # contain data from multiple topics and their partitions because a single client can
65
+ # operate on multiple topics and partitions.
66
+ #
67
+ # We iterate over those topics and partitions and store topics partitions data only.
68
+ #
69
+ # @param group_id [String] id of the group for which statistics were emitted.
70
+ # @param statistics [Hash] librdkafka enriched statistics
71
+ def add(group_id, statistics)
72
+ @mutex.synchronize do
73
+ statistics.fetch("topics", EMPTY_HASH).each do |topic_name, t_details|
74
+ t_details.fetch("partitions", EMPTY_HASH).each do |partition_id, p_details|
75
+ next unless track?(partition_id, p_details)
76
+
77
+ key = "#{group_id}_#{topic_name}_#{partition_id}"
78
+ @accu[key] = [monotonic_now, p_details]
79
+ end
80
+ end
81
+
82
+ evict
83
+ end
84
+ end
85
+
86
+ # Finds statistics about requested consumer group topic partition
87
+ #
88
+ # @param topic [Karafka::Routing::Topic]
89
+ # @param partition [Integer]
90
+ # @return [Hash] hash with given topic partition statistics or empty hash if not present
91
+ #
92
+ # @note We do not enclose it with a mutex mainly because the only thing that could happen
93
+ # here that would be a race-condition is a miss that anyhow we need to support due to
94
+ # how librdkafka ships metrics and a potential removal of data on heavily revoked LRJ.
95
+ def find(topic, partition)
96
+ key = "#{topic.group.id}_#{topic.name}_#{partition}"
97
+ @accu.fetch(key, EMPTY_ARRAY).last || EMPTY_HASH
98
+ end
99
+
100
+ # Clears the tracker
101
+ def clear
102
+ @mutex.synchronize { @accu.clear }
103
+ end
104
+
105
+ private
106
+
107
+ # Evicts expired data from the cache
108
+ def evict
109
+ @accu.delete_if { |_, details| monotonic_now - details.first > TTL }
110
+ end
111
+
112
+ # Should we track given partition
113
+ #
114
+ # We do not track stopped partitions and the once we do not work with actively
115
+ # @param partition_id [String] partition id as a string
116
+ # @param p_details [Hash] partition statistics details
117
+ # @return [Boolean] true if we should track given partition
118
+ def track?(partition_id, p_details)
119
+ return false if partition_id == "-1"
120
+
121
+ fetch_state = p_details.fetch("fetch_state")
122
+
123
+ return false if fetch_state == "stopped"
124
+ return false if fetch_state == "none"
125
+
126
+ true
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Processing
5
+ # Consumer-group-specific processing components (driven by rebalance callbacks and partition
6
+ # ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
7
+ module ConsumerGroups
8
+ # Consumer-group-specific job types
9
+ module Jobs
10
+ # The main job type. It runs the executor that triggers given topic partition messages
11
+ # processing in an underlying consumer instance.
12
+ class Consume < ::Karafka::Processing::Jobs::Base
13
+ # @return [Array<Rdkafka::Consumer::Message>] array with messages
14
+ attr_reader :messages
15
+
16
+ self.action = :consume
17
+
18
+ # @param executor [Karafka::Processing::ConsumerGroups::Executor] executor that is suppose to run a given
19
+ # job
20
+ # @param messages [Karafka::Messages::Messages] karafka messages batch
21
+ # @return [Consume]
22
+ def initialize(executor, messages)
23
+ @executor = executor
24
+ @messages = messages
25
+ super()
26
+ end
27
+
28
+ # Runs all the preparation code on the executor that needs to happen before the job is
29
+ # scheduled.
30
+ def before_schedule
31
+ executor.before_schedule_consume(@messages)
32
+ end
33
+
34
+ # Runs the before consumption preparations on the executor
35
+ def before_call
36
+ executor.before_consume
37
+ end
38
+
39
+ # Runs the given executor
40
+ def call
41
+ executor.consume
42
+ end
43
+
44
+ # Runs any error handling and other post-consumption stuff on the executor
45
+ def after_call
46
+ executor.after_consume
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end