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,157 @@
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 Strategies
9
+ # When using dead letter queue, processing won't stop after defined number of retries
10
+ # upon encountering non-critical errors but the messages that error will be moved to a
11
+ # separate topic with their payload and metadata, so they can be handled differently.
12
+ module Dlq
13
+ include Default
14
+
15
+ # Apply strategy when only dead letter queue is turned on
16
+ FEATURES = %i[
17
+ dead_letter_queue
18
+ ].freeze
19
+
20
+ # Override of the standard `#mark_as_consumed` in order to handle the pause tracker
21
+ # reset in case DLQ is marked as fully independent. When DLQ is marked independent,
22
+ # any offset marking causes the pause count tracker to reset. This is useful when
23
+ # the error is not due to the collective batch operations state but due to intermediate
24
+ # "crawling" errors that move with it
25
+ #
26
+ # @see `Strategies::Default#mark_as_consumed` for more details
27
+ # @param message [Messages::Message]
28
+ def mark_as_consumed(message)
29
+ # If we are not retrying pause count is already 0, no need to try to reset the state
30
+ return super unless retrying?
31
+ # If we do not use independent marking on DLQ, we just mark as consumed
32
+ return super unless topic.dead_letter_queue.independent?
33
+ # If we were not able to mark no need to reset
34
+ return false unless super
35
+
36
+ coordinator.pause_tracker.reset
37
+
38
+ true
39
+ end
40
+
41
+ # Override of the standard `#mark_as_consumed!`. Resets the pause tracker count in case
42
+ # DLQ was configured with the `independent` flag.
43
+ #
44
+ # @see `Strategies::Default#mark_as_consumed!` for more details
45
+ # @param message [Messages::Message]
46
+ def mark_as_consumed!(message)
47
+ return super unless retrying?
48
+ return super unless topic.dead_letter_queue.independent?
49
+ return false unless super
50
+
51
+ coordinator.pause_tracker.reset
52
+
53
+ true
54
+ end
55
+
56
+ # When manual offset management is on, we do not mark anything as consumed automatically
57
+ # and we rely on the user to figure things out
58
+ def handle_after_consume
59
+ return if revoked?
60
+
61
+ if coordinator.success?
62
+ coordinator.pause_tracker.reset
63
+
64
+ return if coordinator.manual_pause?
65
+
66
+ mark_as_consumed(messages.last)
67
+ elsif coordinator.pause_tracker.attempt <= topic.dead_letter_queue.max_retries
68
+ retry_after_pause
69
+ # If we've reached number of retries that we could, we need to skip the first message
70
+ # that was not marked as consumed, pause and continue, while also moving this message
71
+ # to the dead topic
72
+ else
73
+ # We reset the pause to indicate we will now consider it as "ok".
74
+ coordinator.pause_tracker.reset
75
+
76
+ skippable_message, = find_skippable_message
77
+
78
+ # Send skippable message to the dql topic
79
+ dispatch_to_dlq(skippable_message)
80
+
81
+ # We mark the broken message as consumed and move on
82
+ if mark_after_dispatch?
83
+ mark_dispatched_to_dlq(skippable_message)
84
+
85
+ return if revoked?
86
+ else
87
+ self.seek_offset = skippable_message.offset + 1
88
+ end
89
+
90
+ # We pause to backoff once just in case.
91
+ pause(seek_offset, nil, false)
92
+ end
93
+ end
94
+
95
+ # Finds the message may want to skip (all, starting from first)
96
+ # @private
97
+ # @return [Array<Karafka::Messages::Message, Boolean>] message we may want to skip and
98
+ # information if this message was from marked offset or figured out via mom flow
99
+ def find_skippable_message
100
+ skippable_message = messages.raw.find do |msg|
101
+ coordinator.marked? && msg.offset == seek_offset
102
+ end
103
+
104
+ # If we don't have the message matching the last comitted offset, it means that
105
+ # user operates with manual offsets and we're beyond the batch in which things
106
+ # broke for the first time. Then we skip the first (as no markings) and we
107
+ # move on one by one.
108
+ skippable_message ? [skippable_message, true] : [messages.first, false]
109
+ end
110
+
111
+ # Moves the broken message into a separate queue defined via the settings
112
+ # @private
113
+ # @param skippable_message [Karafka::Messages::Message] message we are skipping that also
114
+ # should go to the dlq topic
115
+ def dispatch_to_dlq(skippable_message)
116
+ producer.public_send(
117
+ topic.dead_letter_queue.dispatch_method,
118
+ topic: topic.dead_letter_queue.topic,
119
+ payload: skippable_message.raw_payload
120
+ )
121
+
122
+ # Notify about dispatch on the events bus
123
+ monitor.instrument(
124
+ "dead_letter_queue.dispatched",
125
+ caller: self,
126
+ message: skippable_message
127
+ )
128
+ end
129
+
130
+ # @return [Boolean] should we mark given message as consumed after dispatch. For default
131
+ # non MOM strategies if user did not explicitly tell us not to, we mark it. Default is
132
+ # `nil`, which means `true` in this case. If user provided alternative value, we go
133
+ # with it.
134
+ def mark_after_dispatch?
135
+ return true if topic.dead_letter_queue.mark_after_dispatch.nil?
136
+
137
+ topic.dead_letter_queue.mark_after_dispatch
138
+ end
139
+
140
+ # Marks message that went to DLQ (if applicable) based on the requested method
141
+ # @param skippable_message [Karafka::Messages::Message]
142
+ def mark_dispatched_to_dlq(skippable_message)
143
+ case topic.dead_letter_queue.marking_method
144
+ when :mark_as_consumed
145
+ mark_as_consumed(skippable_message)
146
+ when :mark_as_consumed!
147
+ mark_as_consumed!(skippable_message)
148
+ else
149
+ # This should never happen. Bug if encountered. Please report
150
+ raise Karafka::Errors::UnsupportedCaseError
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,72 @@
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 Strategies
9
+ # Same as pure dead letter queue but we do not marked failed message as consumed
10
+ module DlqMom
11
+ include Dlq
12
+
13
+ # Apply strategy when dlq is on with manual offset management
14
+ FEATURES = %i[
15
+ dead_letter_queue
16
+ manual_offset_management
17
+ ].freeze
18
+
19
+ # When manual offset management is on, we do not mark anything as consumed automatically
20
+ # and we rely on the user to figure things out
21
+ def handle_after_consume
22
+ return if revoked?
23
+
24
+ if coordinator.success?
25
+ coordinator.pause_tracker.reset
26
+ elsif coordinator.pause_tracker.attempt <= topic.dead_letter_queue.max_retries
27
+ retry_after_pause
28
+ # If we've reached number of retries that we could, we need to skip the first message
29
+ # that was not marked as consumed, pause and continue, while also moving this message
30
+ # to the dead topic
31
+ else
32
+ # We reset the pause to indicate we will now consider it as "ok".
33
+ coordinator.pause_tracker.reset
34
+
35
+ skippable_message, = find_skippable_message
36
+
37
+ dispatch_to_dlq(skippable_message)
38
+
39
+ # We mark the broken message as consumed and move on
40
+ if mark_after_dispatch?
41
+ mark_dispatched_to_dlq(skippable_message)
42
+
43
+ return if revoked?
44
+ else
45
+ # Save the next offset we want to go with after moving given message to DLQ
46
+ # Without this, we would not be able to move forward and we would end up
47
+ # in an infinite loop trying to un-pause from the message we've already processed
48
+ # Of course, since it's a MoM a rebalance or kill, will move it back as no
49
+ # offsets are being committed
50
+ self.seek_offset = skippable_message.offset + 1
51
+ end
52
+
53
+ pause(seek_offset, nil, false)
54
+ end
55
+ end
56
+
57
+ # @return [Boolean] should we mark given message as consumed after dispatch. For
58
+ # MOM strategies if user did not explicitly tell us to mark, we do not mark. Default is
59
+ # `nil`, which means `false` in this case. If user provided alternative value, we go
60
+ # with it.
61
+ #
62
+ # @note Please note, this is the opposite behavior than in case of AOM strategies.
63
+ def mark_after_dispatch?
64
+ return false if topic.dead_letter_queue.mark_after_dispatch.nil?
65
+
66
+ topic.dead_letter_queue.mark_after_dispatch
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,33 @@
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 Strategies
9
+ # When using manual offset management, we do not mark as consumed after successful processing
10
+ module Mom
11
+ include Default
12
+
13
+ # Apply strategy when only manual offset management is turned on
14
+ FEATURES = %i[
15
+ manual_offset_management
16
+ ].freeze
17
+
18
+ # When manual offset management is on, we do not mark anything as consumed automatically
19
+ # and we rely on the user to figure things out
20
+ def handle_after_consume
21
+ return if revoked?
22
+
23
+ if coordinator.success?
24
+ coordinator.pause_tracker.reset
25
+ else
26
+ retry_after_pause
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,53 @@
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 processing strategy matching topic combinations
9
+ class StrategySelector
10
+ attr_reader :strategies
11
+
12
+ # Features we support in the OSS offering.
13
+ SUPPORTED_FEATURES = %i[
14
+ active_job
15
+ manual_offset_management
16
+ dead_letter_queue
17
+ ].freeze
18
+
19
+ # Initializes the strategy selector and preloads all strategies
20
+ def initialize
21
+ # We load them once for performance reasons not to do too many lookups
22
+ @strategies = find_all
23
+ end
24
+
25
+ # @param topic [Karafka::Routing::Topic] topic with settings based on which we find
26
+ # strategy
27
+ # @return [Module] module with proper strategy
28
+ def find(topic)
29
+ feature_set = SUPPORTED_FEATURES.map do |feature_name|
30
+ topic.public_send("#{feature_name}?") ? feature_name : nil
31
+ end
32
+
33
+ feature_set.compact!
34
+
35
+ @strategies.find do |strategy|
36
+ strategy::FEATURES.sort == feature_set.sort
37
+ end || raise(Errors::StrategyNotFoundError, topic.name)
38
+ end
39
+
40
+ private
41
+
42
+ # @return [Array<Module>] available strategies
43
+ def find_all
44
+ Strategies
45
+ .constants
46
+ .delete_if { |k| k == :Base }
47
+ .map { |k| Strategies.const_get(k) }
48
+ .uniq
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,217 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Backwards-compatible alias kept for karafka-web gem that references the old, un-namespaced
4
+ # constant. Will be removed in Karafka 3.0.
3
5
  module Karafka
4
6
  module Processing
5
- # Basic coordinator that allows us to provide coordination objects into consumers.
6
- #
7
- # This is a wrapping layer to simplify management of work to be handled around consumption.
8
- #
9
- # @note This coordinator needs to be thread safe. Some operations are performed only in the
10
- # listener thread, but we go with thread-safe by default for all not to worry about potential
11
- # future mistakes.
12
- class Coordinator
13
- extend Forwardable
14
- include Core::Helpers::Time
15
-
16
- attr_reader :pause_tracker, :seek_offset, :topic, :partition
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
-
25
- def_delegators :@pause_tracker, :attempt, :paused?
26
-
27
- # @param topic [Karafka::Routing::Topic]
28
- # @param partition [Integer]
29
- # @param pause_tracker [Karafka::TimeTrackers::Pause] pause tracker for given topic partition
30
- def initialize(topic, partition, pause_tracker)
31
- @topic = topic
32
- @partition = partition
33
- @pause_tracker = pause_tracker
34
- @revoked = false
35
- @consumptions = {}
36
- @running_jobs = Hash.new { |h, k| h[k] = 0 }
37
- @manual_pause = false
38
- @manual_seek = false
39
- @mutex = Mutex.new
40
- @marked = false
41
- @failure = false
42
- @eofed = false
43
- @changed_at = monotonic_now
44
- @last_polled_at = @changed_at
45
- end
46
-
47
- # Starts the coordinator for given consumption jobs
48
- # @param messages [Array<Karafka::Messages::Message>] batch of message for which we are
49
- # going to coordinate work. Not used with regular coordinator.
50
- def start(messages)
51
- @failure = false
52
- @running_jobs[:consume] = 0
53
- # We need to clear the consumption results hash here, otherwise we could end up storing
54
- # consumption results of consumer instances we no longer control
55
- @consumptions.clear
56
-
57
- # When starting to run, no pause is expected and no manual pause as well
58
- @manual_pause = false
59
-
60
- # No user invoked seeks on a new run
61
- @manual_seek = false
62
-
63
- # We set it on the first encounter and never again, because then the offset setting
64
- # should be up to the consumers logic (our or the end user)
65
- # Seek offset needs to be always initialized as for case where manual offset management
66
- # is turned on, we need to have reference to the first offset even in case of running
67
- # multiple batches without marking any messages as consumed. Rollback needs to happen to
68
- # the last place we know of or the last message + 1 that was marked
69
- #
70
- # It is however worth keeping in mind, that this may need to be used with `#marked?` to
71
- # make sure that the first offset is an offset that has been marked.
72
- @seek_offset ||= messages.first.offset
73
- end
74
-
75
- # @param offset [Integer] message offset
76
- def seek_offset=(offset)
77
- synchronize do
78
- @marked = true
79
- @seek_offset = offset
80
- end
81
- end
82
-
83
- # Increases number of jobs that we handle with this coordinator
84
- # @param job_type [Symbol] type of job that we want to increment
85
- def increment(job_type)
86
- synchronize do
87
- @running_jobs[job_type] += 1
88
- @changed_at = monotonic_now
89
- end
90
- end
91
-
92
- # Decrements number of jobs we handle at the moment
93
- # @param job_type [Symbol] type of job that we want to decrement
94
- def decrement(job_type)
95
- synchronize do
96
- @running_jobs[job_type] -= 1
97
- @changed_at = monotonic_now
98
-
99
- return @running_jobs[job_type] unless @running_jobs[job_type].negative?
100
-
101
- # This should never happen. If it does, something is heavily out of sync. Please reach
102
- # out to us if you encounter this
103
- raise Karafka::Errors::InvalidCoordinatorStateError, "Was zero before decrementation"
104
- end
105
- end
106
-
107
- # Is all the consumption done and finished successfully for this coordinator
108
- # We do not say we're successful until all work is done, because running work may still
109
- # crash.
110
- # @note This is only used for consume synchronization
111
- def success?
112
- synchronize do
113
- @running_jobs[:consume].zero? && @consumptions.values.all?(&:success?)
114
- end
115
- end
116
-
117
- # Mark given consumption on consumer as successful
118
- # @param consumer [Karafka::BaseConsumer] consumer that finished successfully
119
- def success!(consumer)
120
- synchronize do
121
- consumption(consumer).success!
122
- end
123
- end
124
-
125
- # Mark given consumption on consumer as failed
126
- # @param consumer [Karafka::BaseConsumer] consumer that failed
127
- # @param error [StandardError] error that occurred
128
- def failure!(consumer, error)
129
- synchronize do
130
- @failure = true
131
- consumption(consumer).failure!(error)
132
- end
133
- end
134
-
135
- # @return [Boolean] true if any of work we were running failed
136
- def failure?
137
- @failure
138
- end
139
-
140
- # Marks given coordinator for processing group as revoked
141
- #
142
- # This is invoked in two places:
143
- # - from the main listener loop when we detect revoked partitions
144
- # - from the consumer in case checkpointing fails
145
- #
146
- # This means, we can end up having consumer being aware that it was revoked prior to the
147
- # listener loop dispatching the revocation job. It is ok, as effectively nothing will be
148
- # processed until revocation jobs are done.
149
- def revoke
150
- synchronize { @revoked = true }
151
- end
152
-
153
- # @return [Boolean] is the partition we are processing revoked or not
154
- def revoked?
155
- @revoked
156
- end
157
-
158
- # @return [Boolean] did we reach end of partition when polling data
159
- def eofed?
160
- @eofed
161
- end
162
-
163
- # @return [Boolean] was the new seek offset assigned at least once. This is needed because
164
- # by default we assign seek offset of a first message ever, however this is insufficient
165
- # for DLQ in a scenario where the first message would be broken. We would never move
166
- # out of it and would end up in an endless loop.
167
- def marked?
168
- @marked
169
- end
170
-
171
- # Store in the coordinator info, that this pause was done manually by the end user and not
172
- # by the system itself
173
- def manual_pause
174
- @manual_pause = true
175
- end
176
-
177
- # @return [Boolean] are we in a pause that was initiated by the user
178
- def manual_pause?
179
- paused? && @manual_pause
180
- end
181
-
182
- # Marks seek as manual for coordination purposes
183
- def manual_seek
184
- @manual_seek = true
185
- end
186
-
187
- # @return [Boolean] did a user invoke seek in the current operations scope
188
- def manual_seek?
189
- @manual_seek
190
- end
191
-
192
- # @param consumer [Object] karafka consumer (normal or pro)
193
- # @return [Karafka::Processing::Result] result object which we can use to indicate
194
- # consumption processing state.
195
- def consumption(consumer)
196
- @consumptions[consumer] ||= Processing::Result.new
197
- end
198
-
199
- # Allows to run synchronized (locked) code that can operate only from a given thread
200
- #
201
- # @note We check if mutex is not owned already by the current thread so we won't end up with
202
- # a deadlock in case user runs coordinated code from inside of his own lock
203
- #
204
- # @note This is internal and should **not** be used to synchronize user-facing code.
205
- # Otherwise user indirectly could cause deadlocks or prolonged locks by running his logic.
206
- # This can and should however be used for multi-thread strategy applications and other
207
- # internal operations locks.
208
- def synchronize(&)
209
- if @mutex.owned?
210
- yield
211
- else
212
- @mutex.synchronize(&)
213
- end
214
- end
215
- end
7
+ # @see ConsumerGroups::Coordinator
8
+ Coordinator = ConsumerGroups::Coordinator
216
9
  end
217
10
  end
@@ -1,65 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Backwards-compatible alias kept for karafka-testing gem that references the old, un-namespaced
4
+ # constant. Will be removed in Karafka 3.0.
3
5
  module Karafka
4
6
  module Processing
5
- # Coordinators builder used to build coordinators per topic partition
6
- #
7
- # It provides direct pauses access for revocation
8
- #
9
- # @note This buffer operates only from the listener loop, thus we do not have to make it
10
- # thread-safe.
11
- class CoordinatorsBuffer
12
- include Helpers::ConfigImporter.new(
13
- coordinator_class: %i[internal processing coordinator_class]
14
- )
15
-
16
- # @param topics [Karafka::Routing::Topics]
17
- def initialize(topics)
18
- @pauses_manager = Connection::PausesManager.new
19
- @coordinators = Hash.new { |h, k| h[k] = {} }
20
- @topics = topics
21
- end
22
-
23
- # @param topic_name [String] topic name
24
- # @param partition [Integer] partition number
25
- # @return [Karafka::Processing::Coordinator] found or created coordinator
26
- def find_or_create(topic_name, partition)
27
- @coordinators[topic_name][partition] ||= begin
28
- routing_topic = @topics.find(topic_name)
29
-
30
- coordinator_class.new(
31
- routing_topic,
32
- partition,
33
- @pauses_manager.fetch(routing_topic, partition)
34
- )
35
- end
36
- end
37
-
38
- # Resumes processing of partitions for which pause time has ended.
39
- # @yieldparam [String] topic name
40
- # @yieldparam [Integer] partition number
41
- def resume(&)
42
- @pauses_manager.resume(&)
43
- end
44
-
45
- # @param topic_name [String] topic name
46
- # @param partition [Integer] partition number
47
- def revoke(topic_name, partition)
48
- return unless @coordinators[topic_name].key?(partition)
49
-
50
- # The fact that we delete here does not change the fact that the executor still holds the
51
- # reference to this coordinator. We delete it here, as we will no longer process any
52
- # new stuff with it and we may need a new coordinator if we regain this partition, but the
53
- # coordinator may still be in use
54
- @coordinators[topic_name].delete(partition).revoke
55
- end
56
-
57
- # Clears coordinators and re-created the pauses manager
58
- # This should be used only for critical errors recovery
59
- def reset
60
- @pauses_manager = Connection::PausesManager.new
61
- @coordinators.clear
62
- end
63
- end
7
+ # @see ConsumerGroups::CoordinatorsBuffer
8
+ CoordinatorsBuffer = ConsumerGroups::CoordinatorsBuffer
64
9
  end
65
10
  end
@@ -14,10 +14,13 @@ module Karafka
14
14
  # we use a single workers poll that can have granular scheduling.
15
15
  class JobsQueue
16
16
  include Helpers::ConfigImporter.new(
17
- concurrency: %i[concurrency],
18
17
  tick_interval: %i[internal tick_interval]
19
18
  )
20
19
 
20
+ # Set via writer because of a circular dependency: the queue must exist before the pool
21
+ # (workers need the queue at construction), but the queue needs the pool for concurrency.
22
+ attr_writer :pool
23
+
21
24
  # @return [Karafka::Processing::JobsQueue]
22
25
  def initialize
23
26
  @queue = Queue.new
@@ -56,10 +59,15 @@ module Karafka
56
59
  #
57
60
  # @param job [Jobs::Base] job that we want to run
58
61
  def <<(job)
59
- # We do not push the job if the queue is closed as it means that it would anyhow not be
60
- # executed
61
62
  return if @queue.closed?
62
63
 
64
+ # nil is used by WorkersPool to signal a worker to exit during downscaling.
65
+ # Passed straight through to the raw queue, bypassing statistics and tracking.
66
+ unless job
67
+ @queue << job
68
+ return
69
+ end
70
+
63
71
  @mutex.synchronize do
64
72
  group = @in_processing[job.group_id]
65
73
 
@@ -70,7 +78,7 @@ module Karafka
70
78
  # Assume that moving to queue means being picked up immediately not to create stats
71
79
  # race conditions because of pop overhead. If there are workers available, we assume
72
80
  # work is going to be handled as we never reject enqueued jobs
73
- if @statistics[:busy] < concurrency
81
+ if @statistics[:busy] < @pool.size
74
82
  @statistics[:busy] += 1
75
83
  else
76
84
  # If system is fully loaded, it means this job is indeed enqueued
@@ -1,24 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Backwards-compatible alias kept for external code that references the old, un-namespaced
4
+ # constant. Will be removed in Karafka 3.0.
3
5
  module Karafka
4
6
  module Processing
5
- # Basic partitioner for work division
6
- # It does not divide any work.
7
- class Partitioner
8
- # @param subscription_group [Karafka::Routing::SubscriptionGroup] subscription group
9
- def initialize(subscription_group)
10
- @subscription_group = subscription_group
11
- end
12
-
13
- # @param _topic [String] topic name
14
- # @param messages [Array<Karafka::Messages::Message>] karafka messages
15
- # @param _coordinator [Karafka::Processing::Coordinator] processing coordinator that will
16
- # be used with those messages
17
- # @yieldparam [Integer] group id
18
- # @yieldparam [Array<Karafka::Messages::Message>] karafka messages
19
- def call(_topic, messages, _coordinator)
20
- yield(0, messages)
21
- end
22
- end
7
+ # @see ConsumerGroups::Partitioner
8
+ Partitioner = ConsumerGroups::Partitioner
23
9
  end
24
10
  end
@@ -13,7 +13,8 @@ module Karafka
13
13
 
14
14
  # Schedules jobs in the fifo order
15
15
  #
16
- # @param jobs_array [Array<Karafka::Processing::Jobs::Consume>] jobs we want to schedule
16
+ # @param jobs_array [Array<Karafka::Processing::ConsumerGroups::Jobs::Consume>] jobs we
17
+ # want to schedule
17
18
  def on_schedule_consumption(jobs_array)
18
19
  jobs_array.each do |job|
19
20
  @queue << job