karafka 2.4.0 → 2.4.18

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