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
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code is part of Karafka Pro, a commercial component not licensed under LGPL.
4
+ # See LICENSE for details.
5
+
6
+ module Karafka
7
+ module Pro
8
+ module ScheduledMessages
9
+ # Consumer that coordinates scheduling of messages when the time comes
10
+ class Consumer < ::Karafka::BaseConsumer
11
+ # Prepares the initial state of all stateful components
12
+ def initialized
13
+ clear!
14
+ # Max epoch is always moving forward with the time. Never backwards, hence we do not
15
+ # reset it at all.
16
+ @max_epoch = MaxEpoch.new
17
+ @state = State.new(nil)
18
+ end
19
+
20
+ # Processes messages and runs dispatch (via tick) if needed
21
+ def consume
22
+ return if reload!
23
+
24
+ messages.each do |message|
25
+ SchemaValidator.call(message)
26
+ process_message(message)
27
+ end
28
+
29
+ @states_reporter.call
30
+
31
+ eofed if eofed?
32
+
33
+ # Unless given day data is fully loaded we should not dispatch any notifications nor
34
+ # should we mark messages.
35
+ return unless @state.loaded?
36
+
37
+ tick
38
+
39
+ # Despite the fact that we need to load the whole stream once a day we do mark.
40
+ # We mark as consumed for two main reasons:
41
+ # - by marking we can indicate to Web UI and other monitoring tools that we have a
42
+ # potential real lag with loading schedules in case there would be a lot of messages
43
+ # added to the schedules topic
44
+ # - we prevent a situation where there is no notion of this consumer group in the
45
+ # reporting, allowing us to establish "presence"
46
+ mark_as_consumed(messages.last)
47
+ end
48
+
49
+ # Runs end of file operations
50
+ def eofed
51
+ return if reload!
52
+
53
+ # If end of the partition is reached, it always means all data is loaded
54
+ @state.loaded!
55
+ @states_reporter.call
56
+ end
57
+
58
+ # Performs periodic operations when no new data is provided to the topic partition
59
+ def tick
60
+ return if reload!
61
+
62
+ # We should not dispatch any data until the whole state is loaded. We need to make sure,
63
+ # that all tombstone events are loaded not to duplicate dispatches
64
+ return unless @state.loaded?
65
+
66
+ keys = []
67
+ epochs = []
68
+
69
+ # We first collect all the data for dispatch and then dispatch and **only** after
70
+ # dispatch that is sync is successful we remove those messages from the daily buffer
71
+ # and update the max epoch. Since only the dispatch itself is volatile and can crash
72
+ # with timeouts, etc, we need to be sure it wen through prior to deleting those messages
73
+ # from the daily buffer. That way we ensure the at least once delivery and in case of
74
+ # a transactional producer, exactly once delivery.
75
+ @daily_buffer.for_dispatch do |epoch, message|
76
+ epochs << epoch
77
+ keys << message.key
78
+ @dispatcher << message
79
+ end
80
+
81
+ @dispatcher.flush
82
+
83
+ @max_epoch.update(epochs.max)
84
+
85
+ keys.each { |key| @daily_buffer.delete(key) }
86
+
87
+ @states_reporter.call
88
+ end
89
+
90
+ private
91
+
92
+ # Takes each message and adds it to the daily accumulator if needed or performs other
93
+ # accumulator and time related per-message operations.
94
+ # @param message [Karafka::Messages::Message]
95
+ def process_message(message)
96
+ # If we started to receive messages younger than the moment we created the consumer for
97
+ # the given day, it means we have loaded all the history and we are no longer in the
98
+ # loading phase.
99
+ if message.timestamp.to_i > @today.created_at
100
+ @state.loaded!
101
+ tags.add(:state, @state.to_s)
102
+ end
103
+
104
+ # If this is a schedule message we need to check if this is for today. Tombstone events
105
+ # are always considered immediate as they indicate, that a message with a given key
106
+ # was already dispatched or that user decided not to dispatch and cancelled the dispatch
107
+ # via tombstone publishing.
108
+ if message.headers['schedule_source_type'] == 'schedule'
109
+ time = message.headers['schedule_target_epoch']
110
+
111
+ # Do not track historical below today as those will be reflected in the daily buffer
112
+ @tracker.track(message) if time >= @today.starts_at
113
+
114
+ if time > @today.ends_at || time < @max_epoch.to_i
115
+ # Clean the message immediately when not needed (won't be scheduled) to preserve
116
+ # memory
117
+ message.clean!
118
+
119
+ return
120
+ end
121
+ end
122
+
123
+ # Add to buffer all tombstones and messages for the same day
124
+ @daily_buffer << message
125
+ end
126
+
127
+ # Moves the offset back and re-seeks and reloads the current day not dispatched assignments
128
+ def reload!
129
+ # If this is a new assignment we always need to seek from beginning to load the data
130
+ if @state.fresh?
131
+ clear!
132
+ seek(0)
133
+
134
+ return true
135
+ end
136
+
137
+ # Unless state is loaded we do not do anything more because we're in the loading process
138
+ return false unless @state.loaded?
139
+
140
+ # If day has ended we reload and start new day with new schedules
141
+ if @today.ended?
142
+ clear!
143
+ seek(0)
144
+
145
+ return true
146
+ end
147
+
148
+ false
149
+ end
150
+
151
+ # Resets all buffers and states so we can start a new day with a clean slate
152
+ # We can fully recreate the dispatcher because any undispatched messages will be dispatched
153
+ # with the new day dispatcher after it is reloaded.
154
+ def clear!
155
+ @daily_buffer = DailyBuffer.new
156
+ @today = Day.new
157
+ @tracker = Tracker.new
158
+ @state = State.new(false)
159
+ @dispatcher = config.dispatcher_class.new(topic.name, partition)
160
+ @states_reporter = Helpers::IntervalRunner.new do
161
+ @tracker.today = @daily_buffer.size
162
+ @tracker.state = @state.to_s
163
+
164
+ @dispatcher.state(@tracker)
165
+ end
166
+
167
+ tags.add(:state, @state.to_s)
168
+ end
169
+
170
+ # @return [Karafka::Core::Configurable::Node] Schedules config node
171
+ def config
172
+ @config ||= Karafka::App.config.scheduled_messages
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code is part of Karafka Pro, a commercial component not licensed under LGPL.
4
+ # See LICENSE for details.
5
+
6
+ module Karafka
7
+ module Pro
8
+ module ScheduledMessages
9
+ # Recurring Tasks related contracts
10
+ module Contracts
11
+ # Makes sure, all the expected config is defined as it should be
12
+ class Config < ::Karafka::Contracts::Base
13
+ configure do |config|
14
+ config.error_messages = YAML.safe_load(
15
+ File.read(
16
+ File.join(Karafka.gem_root, 'config', 'locales', 'pro_errors.yml')
17
+ )
18
+ ).fetch('en').fetch('validations').fetch('config')
19
+ end
20
+
21
+ nested(:scheduled_messages) do
22
+ required(:consumer_class) { |val| val < ::Karafka::BaseConsumer }
23
+
24
+ # Do not allow to run more often than every second
25
+ required(:interval) { |val| val.is_a?(Integer) && val >= 1_000 }
26
+
27
+ required(:flush_batch_size) { |val| val.is_a?(Integer) && val.positive? }
28
+
29
+ required(:dispatcher_class) { |val| !val.nil? }
30
+
31
+ required(:group_id) do |val|
32
+ val.is_a?(String) && Karafka::Contracts::TOPIC_REGEXP.match?(val)
33
+ end
34
+
35
+ required(:states_postfix) do |val|
36
+ val.is_a?(String) && Karafka::Contracts::TOPIC_REGEXP.match?(val)
37
+ end
38
+
39
+ nested(:deserializers) do
40
+ required(:headers) { |val| !val.nil? }
41
+ required(:payload) { |val| !val.nil? }
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code is part of Karafka Pro, a commercial component not licensed under LGPL.
4
+ # See LICENSE for details.
5
+
6
+ module Karafka
7
+ module Pro
8
+ module ScheduledMessages
9
+ module Contracts
10
+ # Future message expected format.
11
+ #
12
+ # Our envelope always needs to comply with this format, otherwise we won't have enough
13
+ # details to be able to dispatch the message
14
+ class Message < ::Karafka::Contracts::Base
15
+ configure do |config|
16
+ config.error_messages = YAML.safe_load(
17
+ File.read(
18
+ File.join(Karafka.gem_root, 'config', 'locales', 'pro_errors.yml')
19
+ )
20
+ ).fetch('en').fetch('validations').fetch('scheduled_messages_message')
21
+ end
22
+
23
+ # Headers we expect in each message of type "schedule" that goes to our scheduled
24
+ # messages topic
25
+ EXPECTED_SCHEDULE_HEADERS = %w[
26
+ schedule_schema_version
27
+ schedule_target_epoch
28
+ schedule_source_type
29
+ schedule_target_topic
30
+ ].freeze
31
+
32
+ # Headers we expect in each message of type "cancel"
33
+ EXPECTED_CANCEL_HEADERS = %w[
34
+ schedule_schema_version
35
+ schedule_source_type
36
+ ].freeze
37
+
38
+ required(:key) { |val| val.is_a?(String) && val.size.positive? }
39
+
40
+ # Ensure that schedule has all correct keys and that others have other related data
41
+ required(:headers) do |val|
42
+ next false unless val.is_a?(Hash)
43
+
44
+ if val['schedule_source_type'] == 'message'
45
+ (val.keys & EXPECTED_SCHEDULE_HEADERS).size >= 4
46
+ else
47
+ (val.keys & EXPECTED_CANCEL_HEADERS).size >= 2
48
+ end
49
+ end
50
+
51
+ # Make sure, that schedule_target_epoch is not older than grace period behind us.
52
+ # While this is not ideal verification of scheduling stuff in past, at leats it will
53
+ # prevent user errors when they schedule at 0, etc
54
+ virtual do |data, errors|
55
+ next unless errors.empty?
56
+
57
+ # Validate epoch only for schedules
58
+ next unless data[:headers]['schedule_source_type'] == 'schedule'
59
+
60
+ epoch_time = data[:headers].fetch('schedule_target_epoch').to_i
61
+
62
+ # We allow for small lag as those will be dispatched but we should prevent dispatching
63
+ # in the past in general as often it is a source of errors
64
+ next if epoch_time >= Time.now.to_i - 10
65
+
66
+ [[[:headers], :schedule_target_epoch_in_the_past]]
67
+ end
68
+
69
+ # Makes sure, that the target envelope topic we dispatch to is a scheduled messages topic
70
+ virtual do |data, errors|
71
+ next unless errors.empty?
72
+
73
+ scheduled_topics = Karafka::App
74
+ .routes
75
+ .flat_map(&:topics)
76
+ .flat_map(&:to_a)
77
+ .select(&:scheduled_messages?)
78
+ .map(&:name)
79
+
80
+ next if scheduled_topics.include?(data[:topic].to_s)
81
+
82
+ [[[:topic], :not_a_scheduled_messages_topic]]
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code is part of Karafka Pro, a commercial component not licensed under LGPL.
4
+ # See LICENSE for details.
5
+
6
+ module Karafka
7
+ module Pro
8
+ module ScheduledMessages
9
+ # Stores schedules for the current day and gives back those that should be dispatched
10
+ # We do not use min-heap implementation and just a regular hash because we want to be able
11
+ # to update the schedules based on the key as well as remove the schedules in case it would
12
+ # be cancelled. While removals could be implemented, updates with different timestamp would
13
+ # be more complex. At the moment a lookup of 8 640 000 messages (100 per second) takes
14
+ # up to 1.5 second, thus it is acceptable. Please ping me if you encounter performance
15
+ # issues with this naive implementation so it can be improved.
16
+ class DailyBuffer
17
+ def initialize
18
+ @accu = {}
19
+ end
20
+
21
+ # @return [Integer] number of elements to schedule today
22
+ def size
23
+ @accu.size
24
+ end
25
+
26
+ # Adds message to the buffer or removes the message from the buffer if it is a tombstone
27
+ # message for a given key
28
+ #
29
+ # @param message [Karafka::Messages::Message]
30
+ #
31
+ # @note Only messages for a given day should be added here.
32
+ def <<(message)
33
+ # Non schedule are only tombstones and cancellations
34
+ schedule = message.headers['schedule_source_type'] == 'schedule'
35
+
36
+ key = message.key
37
+
38
+ if schedule
39
+ epoch = message.headers['schedule_target_epoch']
40
+ @accu[key] = [epoch, message]
41
+ else
42
+ @accu.delete(key)
43
+ end
44
+ end
45
+
46
+ # Yields messages that should be dispatched (sent) to Kafka
47
+ #
48
+ # @yieldparam [Integer, Karafka::Messages::Message] epoch of the message and the message
49
+ # itself
50
+ #
51
+ # @note We yield epoch alongside of the message so we do not have to extract it several
52
+ # times later on. This simplifies the API
53
+ def for_dispatch
54
+ dispatch = Time.now.to_i
55
+
56
+ @accu.each_value do |epoch, message|
57
+ next unless epoch <= dispatch
58
+
59
+ yield(epoch, message)
60
+ end
61
+ end
62
+
63
+ # Removes given key from the accumulator
64
+ # @param key [String] key to remove
65
+ def delete(key)
66
+ @accu.delete(key)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code is part of Karafka Pro, a commercial component not licensed under LGPL.
4
+ # See LICENSE for details.
5
+
6
+ module Karafka
7
+ module Pro
8
+ module ScheduledMessages
9
+ # Just a simple UTC day implementation.
10
+ # Since we operate on a scope of one day, this allows us to encapsulate when given day ends
11
+ class Day
12
+ # @return [Integer] utc timestamp when this day object was created. Keep in mind, that
13
+ # this is **not** when the day started but when this object was created.
14
+ attr_reader :created_at
15
+ # @return [Integer] utc timestamp when this day ends (last second of day).
16
+ # Equal to 23:59:59.
17
+ attr_reader :ends_at
18
+ # @return [Integer] utc timestamp when this day starts. Equal to 00:00:00
19
+ attr_reader :starts_at
20
+
21
+ def initialize
22
+ @created_at = Time.now.to_i
23
+
24
+ time = Time.at(@created_at).utc
25
+
26
+ @starts_at = Time.utc(time.year, time.month, time.day).to_i
27
+ @ends_at = @starts_at + 86_399
28
+ end
29
+
30
+ # @return [Boolean] did the current day we operate on ended.
31
+ def ended?
32
+ @ends_at < Time.now.to_i
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code is part of Karafka Pro, a commercial component not licensed under LGPL.
4
+ # See LICENSE for details.
5
+
6
+ module Karafka
7
+ module Pro
8
+ module ScheduledMessages
9
+ # Namespace for schedules data related deserializers.
10
+ module Deserializers
11
+ # Converts certain pieces of headers into their integer form for messages
12
+ class Headers
13
+ # @param metadata [Karafka::aMessages::Metadata]
14
+ # @return [Hash] headers
15
+ def call(metadata)
16
+ raw_headers = metadata.raw_headers
17
+
18
+ type = raw_headers.fetch('schedule_source_type')
19
+
20
+ # tombstone and cancellation events are not operable, thus we do not have to cast any
21
+ # of the headers pieces
22
+ return raw_headers unless type == 'schedule'
23
+
24
+ headers = raw_headers.dup
25
+ headers['schedule_target_epoch'] = headers['schedule_target_epoch'].to_i
26
+
27
+ # This attribute is optional, this is why we have to check for its existence
28
+ if headers.key?('schedule_target_partition')
29
+ headers['schedule_target_partition'] = headers['schedule_target_partition'].to_i
30
+ end
31
+
32
+ headers
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code is part of Karafka Pro, a commercial component not licensed under LGPL.
4
+ # See LICENSE for details.
5
+
6
+ module Karafka
7
+ module Pro
8
+ module ScheduledMessages
9
+ module Deserializers
10
+ # States payload deserializer
11
+ # We only deserialize states data and never anything else. Other payloads are the payloads
12
+ # we are expected to proxy, thus there is no need to deserialize them in any context.
13
+ # Their appropriate target topics should have expected deserializers
14
+ class Payload
15
+ # @param message [::Karafka::Messages::Message]
16
+ # @return [Hash] deserialized data
17
+ def call(message)
18
+ ::JSON.parse(
19
+ Zlib::Inflate.inflate(message.raw_payload),
20
+ symbolize_names: true
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code is part of Karafka Pro, a commercial component not licensed under LGPL.
4
+ # See LICENSE for details.
5
+
6
+ module Karafka
7
+ module Pro
8
+ module ScheduledMessages
9
+ # Dispatcher responsible for dispatching the messages to appropriate target topics and for
10
+ # dispatching other messages. All messages (aside from the once users dispatch with the
11
+ # envelope) are sent via this dispatcher.
12
+ #
13
+ # Messages are buffered and dispatched in batches to improve dispatch performance.
14
+ class Dispatcher
15
+ # @return [Array<Hash>] buffer with message hashes for dispatch
16
+ attr_reader :buffer
17
+
18
+ # @param topic [String] consumed topic name
19
+ # @param partition [Integer] consumed partition
20
+ def initialize(topic, partition)
21
+ @topic = topic
22
+ @partition = partition
23
+ @buffer = []
24
+ @serializer = Serializer.new
25
+ end
26
+
27
+ # Prepares the scheduled message to the dispatch to the target topic. Extracts all the
28
+ # "schedule_" details and prepares it, so the dispatched message goes with the expected
29
+ # attributes to the desired location. Alongside of that it actually builds 2
30
+ # (1 if logs off) messages: tombstone event matching the schedule so it is no longer valid
31
+ # and the log message that has the same data as the dispatched message. Helpful when
32
+ # debugging.
33
+ #
34
+ # @param message [Karafka::Messages::Message] message from the schedules topic.
35
+ #
36
+ # @note This method adds the message to the buffer, does **not** dispatch it.
37
+ # @note It also produces needed tombstone event as well as an audit log message
38
+ def <<(message)
39
+ target_headers = message.raw_headers.merge(
40
+ 'schedule_source_topic' => @topic,
41
+ 'schedule_source_partition' => @partition.to_s,
42
+ 'schedule_source_offset' => message.offset.to_s,
43
+ 'schedule_source_key' => message.key
44
+ ).compact
45
+
46
+ target = {
47
+ payload: message.raw_payload,
48
+ headers: target_headers
49
+ }
50
+
51
+ extract(target, message.headers, :topic)
52
+ extract(target, message.headers, :partition)
53
+ extract(target, message.headers, :key)
54
+ extract(target, message.headers, :partition_key)
55
+
56
+ @buffer << target
57
+
58
+ # Tombstone message so this schedule is no longer in use and gets removed from Kafka by
59
+ # Kafka itself during compacting. It will not cancel it because already dispatched but
60
+ # will cause it not to be sent again and will be marked as dispatched.
61
+ @buffer << Proxy.tombstone(message: message)
62
+ end
63
+
64
+ # Builds and dispatches the state report message with schedules details
65
+ #
66
+ # @param tracker [Tracker]
67
+ #
68
+ # @note This is dispatched async because it's just a statistical metric.
69
+ def state(tracker)
70
+ config.producer.produce_async(
71
+ topic: "#{@topic}#{config.states_postfix}",
72
+ payload: @serializer.state(tracker),
73
+ key: 'state',
74
+ partition: @partition,
75
+ headers: { 'zlib' => 'true' }
76
+ )
77
+ end
78
+
79
+ # Sends all messages to Kafka in a sync way.
80
+ # We use sync with batches to prevent overloading.
81
+ # When transactional producer in use, this will be wrapped in a transaction automatically.
82
+ def flush
83
+ until @buffer.empty?
84
+ config.producer.produce_many_sync(
85
+ # We can remove this prior to the dispatch because we only evict messages from the
86
+ # daily buffer once dispatch is successful
87
+ @buffer.shift(config.flush_batch_size)
88
+ )
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ # @return [Karafka::Core::Configurable::Node] scheduled messages config node
95
+ def config
96
+ @config ||= Karafka::App.config.scheduled_messages
97
+ end
98
+
99
+ # Extracts and copies the future attribute to a proper place in the target message.
100
+ #
101
+ # @param target [Hash]
102
+ # @param headers [Hash]
103
+ # @param attribute [Symbol]
104
+ def extract(target, headers, attribute)
105
+ schedule_attribute = "schedule_target_#{attribute}"
106
+
107
+ return unless headers.key?(schedule_attribute)
108
+
109
+ target[attribute] = headers[schedule_attribute]
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code is part of Karafka Pro, a commercial component not licensed under LGPL.
4
+ # See LICENSE for details.
5
+
6
+ module Karafka
7
+ module Pro
8
+ module ScheduledMessages
9
+ # Scheduled Messages related errors
10
+ module Errors
11
+ # Base for all the recurring tasks errors
12
+ BaseError = Class.new(::Karafka::Errors::BaseError)
13
+
14
+ # Raised when the scheduled messages processor is older than the messages we started to
15
+ # receive. In such cases we stop because there may be schema changes.
16
+ IncompatibleSchemaError = Class.new(BaseError)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code is part of Karafka Pro, a commercial component not licensed under LGPL.
4
+ # See LICENSE for details.
5
+
6
+ module Karafka
7
+ module Pro
8
+ module ScheduledMessages
9
+ # Simple max value accumulator. When we dispatch messages we can store the max timestamp
10
+ # until which messages were dispatched by us. This allows us to quickly skip those messages
11
+ # during recovery, because we do know, they were dispatched.
12
+ class MaxEpoch
13
+ def initialize
14
+ @max = -1
15
+ end
16
+
17
+ # Updates epoch if bigger than current max
18
+ # @param new_max [Integer] potential new max epoch
19
+ def update(new_max)
20
+ return unless new_max
21
+ return unless new_max > @max
22
+
23
+ @max = new_max
24
+ end
25
+
26
+ # @return [Integer] max epoch recorded
27
+ def to_i
28
+ @max
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end