karafka 2.5.1 → 2.5.3

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 (238) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci_linux_ubuntu_x86_64_gnu.yml +21 -29
  3. data/.github/workflows/ci_macos_arm64.yml +1 -1
  4. data/.github/workflows/push.yml +2 -2
  5. data/.github/workflows/trigger-wiki-refresh.yml +1 -1
  6. data/.ruby-version +1 -1
  7. data/.yard-lint.yml +174 -0
  8. data/CHANGELOG.md +20 -4
  9. data/Gemfile +1 -2
  10. data/Gemfile.lock +45 -41
  11. data/bin/integrations +2 -1
  12. data/bin/rspecs +4 -0
  13. data/config/locales/errors.yml +6 -4
  14. data/config/locales/pro_errors.yml +5 -4
  15. data/docker-compose.yml +1 -1
  16. data/examples/payloads/json/sample_set_02/download.json +191 -0
  17. data/examples/payloads/json/sample_set_03/event_type_1.json +18 -0
  18. data/examples/payloads/json/sample_set_03/event_type_2.json +263 -0
  19. data/examples/payloads/json/sample_set_03/event_type_3.json +41 -0
  20. data/karafka.gemspec +3 -3
  21. data/lib/active_job/queue_adapters/karafka_adapter.rb +3 -3
  22. data/lib/karafka/active_job/consumer.rb +7 -3
  23. data/lib/karafka/active_job/current_attributes/job_wrapper.rb +45 -0
  24. data/lib/karafka/active_job/current_attributes/loading.rb +1 -1
  25. data/lib/karafka/active_job/current_attributes/persistence.rb +19 -7
  26. data/lib/karafka/active_job/current_attributes.rb +3 -2
  27. data/lib/karafka/active_job/deserializer.rb +61 -0
  28. data/lib/karafka/active_job/dispatcher.rb +34 -14
  29. data/lib/karafka/active_job/job_options_contract.rb +2 -4
  30. data/lib/karafka/admin/acl.rb +8 -4
  31. data/lib/karafka/admin/configs/config.rb +6 -4
  32. data/lib/karafka/admin/configs/resource.rb +7 -1
  33. data/lib/karafka/admin/consumer_groups.rb +80 -12
  34. data/lib/karafka/admin/topics.rb +43 -9
  35. data/lib/karafka/admin.rb +23 -14
  36. data/lib/karafka/app.rb +3 -3
  37. data/lib/karafka/base_consumer.rb +6 -6
  38. data/lib/karafka/cli/base.rb +2 -2
  39. data/lib/karafka/cli/console.rb +1 -1
  40. data/lib/karafka/cli/contracts/server.rb +3 -5
  41. data/lib/karafka/cli/help.rb +1 -1
  42. data/lib/karafka/cli/install.rb +3 -2
  43. data/lib/karafka/cli/server.rb +1 -1
  44. data/lib/karafka/cli/swarm.rb +1 -1
  45. data/lib/karafka/cli/topics/align.rb +1 -1
  46. data/lib/karafka/cli/topics/repartition.rb +2 -2
  47. data/lib/karafka/connection/client.rb +30 -19
  48. data/lib/karafka/connection/listeners_batch.rb +2 -3
  49. data/lib/karafka/connection/manager.rb +1 -0
  50. data/lib/karafka/connection/proxy.rb +12 -8
  51. data/lib/karafka/connection/rebalance_manager.rb +1 -1
  52. data/lib/karafka/connection/status.rb +1 -0
  53. data/lib/karafka/constraints.rb +1 -1
  54. data/lib/karafka/contracts/base.rb +1 -1
  55. data/lib/karafka/deserializers/payload.rb +1 -1
  56. data/lib/karafka/env.rb +1 -2
  57. data/lib/karafka/helpers/async.rb +1 -1
  58. data/lib/karafka/helpers/config_importer.rb +3 -3
  59. data/lib/karafka/helpers/interval_runner.rb +4 -1
  60. data/lib/karafka/helpers/multi_delegator.rb +3 -0
  61. data/lib/karafka/instrumentation/assignments_tracker.rb +19 -1
  62. data/lib/karafka/instrumentation/callbacks/error.rb +2 -2
  63. data/lib/karafka/instrumentation/callbacks/statistics.rb +3 -3
  64. data/lib/karafka/instrumentation/logger.rb +6 -6
  65. data/lib/karafka/instrumentation/monitor.rb +3 -3
  66. data/lib/karafka/instrumentation/notifications.rb +1 -0
  67. data/lib/karafka/instrumentation/vendors/appsignal/base.rb +3 -4
  68. data/lib/karafka/instrumentation/vendors/datadog/logger_listener.rb +3 -4
  69. data/lib/karafka/instrumentation/vendors/datadog/metrics_listener.rb +10 -11
  70. data/lib/karafka/instrumentation/vendors/kubernetes/base_listener.rb +1 -1
  71. data/lib/karafka/instrumentation/vendors/kubernetes/liveness_listener.rb +5 -18
  72. data/lib/karafka/messages/builders/batch_metadata.rb +2 -2
  73. data/lib/karafka/messages/builders/message.rb +1 -1
  74. data/lib/karafka/messages/messages.rb +2 -3
  75. data/lib/karafka/patches/rdkafka/bindings.rb +6 -6
  76. data/lib/karafka/patches/rdkafka/opaque.rb +1 -1
  77. data/lib/karafka/pro/active_job/consumer.rb +2 -2
  78. data/lib/karafka/pro/active_job/dispatcher.rb +10 -6
  79. data/lib/karafka/pro/active_job/job_options_contract.rb +2 -4
  80. data/lib/karafka/pro/cleaner/messages/messages.rb +2 -3
  81. data/lib/karafka/pro/cleaner.rb +3 -3
  82. data/lib/karafka/pro/cli/contracts/server.rb +3 -5
  83. data/lib/karafka/pro/cli/parallel_segments/base.rb +5 -5
  84. data/lib/karafka/pro/cli/parallel_segments/collapse.rb +3 -3
  85. data/lib/karafka/pro/cli/parallel_segments/distribute.rb +3 -3
  86. data/lib/karafka/pro/cli/parallel_segments.rb +1 -1
  87. data/lib/karafka/pro/connection/manager.rb +3 -4
  88. data/lib/karafka/pro/connection/multiplexing/listener.rb +1 -0
  89. data/lib/karafka/pro/contracts/base.rb +1 -1
  90. data/lib/karafka/pro/encryption/cipher.rb +3 -2
  91. data/lib/karafka/pro/encryption/contracts/config.rb +5 -7
  92. data/lib/karafka/pro/encryption/messages/parser.rb +4 -4
  93. data/lib/karafka/pro/encryption/setup/config.rb +1 -1
  94. data/lib/karafka/pro/instrumentation/performance_tracker.rb +3 -3
  95. data/lib/karafka/pro/iterator/expander.rb +1 -1
  96. data/lib/karafka/pro/iterator/tpl_builder.rb +2 -2
  97. data/lib/karafka/pro/iterator.rb +3 -3
  98. data/lib/karafka/pro/loader.rb +1 -1
  99. data/lib/karafka/pro/processing/coordinator.rb +1 -1
  100. data/lib/karafka/pro/processing/coordinators/errors_tracker.rb +2 -3
  101. data/lib/karafka/pro/processing/coordinators/filters_applier.rb +3 -3
  102. data/lib/karafka/pro/processing/filters/base.rb +1 -0
  103. data/lib/karafka/pro/processing/filters/delayer.rb +1 -1
  104. data/lib/karafka/pro/processing/filters/expirer.rb +1 -1
  105. data/lib/karafka/pro/processing/filters/inline_insights_delayer.rb +1 -1
  106. data/lib/karafka/pro/processing/filters/throttler.rb +1 -1
  107. data/lib/karafka/pro/processing/jobs/consume_non_blocking.rb +1 -1
  108. data/lib/karafka/pro/processing/jobs/eofed_non_blocking.rb +1 -1
  109. data/lib/karafka/pro/processing/jobs/periodic.rb +1 -1
  110. data/lib/karafka/pro/processing/jobs/revoked_non_blocking.rb +1 -1
  111. data/lib/karafka/pro/processing/jobs_builder.rb +1 -1
  112. data/lib/karafka/pro/processing/offset_metadata/fetcher.rb +1 -0
  113. data/lib/karafka/pro/processing/partitioner.rb +1 -1
  114. data/lib/karafka/pro/processing/schedulers/default.rb +2 -4
  115. data/lib/karafka/pro/processing/strategies/base.rb +1 -1
  116. data/lib/karafka/pro/processing/strategies/default.rb +2 -2
  117. data/lib/karafka/pro/processing/strategies/lrj/default.rb +2 -4
  118. data/lib/karafka/pro/processing/strategies/vp/default.rb +2 -4
  119. data/lib/karafka/pro/processing/strategy_selector.rb +1 -0
  120. data/lib/karafka/pro/processing/subscription_groups_coordinator.rb +2 -3
  121. data/lib/karafka/pro/processing/virtual_partitions/distributors/balanced.rb +4 -2
  122. data/lib/karafka/pro/processing/virtual_partitions/distributors/consistent.rb +4 -2
  123. data/lib/karafka/pro/recurring_tasks/consumer.rb +3 -2
  124. data/lib/karafka/pro/recurring_tasks/contracts/config.rb +4 -6
  125. data/lib/karafka/pro/recurring_tasks/contracts/task.rb +3 -5
  126. data/lib/karafka/pro/recurring_tasks/deserializer.rb +1 -1
  127. data/lib/karafka/pro/recurring_tasks/dispatcher.rb +7 -6
  128. data/lib/karafka/pro/recurring_tasks/executor.rb +2 -1
  129. data/lib/karafka/pro/recurring_tasks/schedule.rb +9 -8
  130. data/lib/karafka/pro/recurring_tasks/serializer.rb +6 -5
  131. data/lib/karafka/pro/recurring_tasks/setup/config.rb +2 -2
  132. data/lib/karafka/pro/recurring_tasks/task.rb +1 -1
  133. data/lib/karafka/pro/recurring_tasks.rb +8 -5
  134. data/lib/karafka/pro/routing/features/adaptive_iterator/contracts/topic.rb +2 -4
  135. data/lib/karafka/pro/routing/features/dead_letter_queue/contracts/topic.rb +2 -4
  136. data/lib/karafka/pro/routing/features/dead_letter_queue/topic.rb +3 -0
  137. data/lib/karafka/pro/routing/features/delaying/contracts/topic.rb +2 -4
  138. data/lib/karafka/pro/routing/features/delaying/topic.rb +2 -4
  139. data/lib/karafka/pro/routing/features/direct_assignments/contracts/consumer_group.rb +4 -8
  140. data/lib/karafka/pro/routing/features/direct_assignments/contracts/topic.rb +5 -7
  141. data/lib/karafka/pro/routing/features/direct_assignments/subscription_group.rb +7 -6
  142. data/lib/karafka/pro/routing/features/direct_assignments/topic.rb +2 -2
  143. data/lib/karafka/pro/routing/features/expiring/contracts/topic.rb +2 -4
  144. data/lib/karafka/pro/routing/features/expiring/topic.rb +2 -4
  145. data/lib/karafka/pro/routing/features/filtering/contracts/topic.rb +2 -4
  146. data/lib/karafka/pro/routing/features/filtering/topic.rb +2 -3
  147. data/lib/karafka/pro/routing/features/inline_insights/contracts/topic.rb +2 -4
  148. data/lib/karafka/pro/routing/features/long_running_job/contracts/topic.rb +2 -4
  149. data/lib/karafka/pro/routing/features/multiplexing/contracts/topic.rb +3 -5
  150. data/lib/karafka/pro/routing/features/multiplexing/subscription_groups_builder.rb +1 -1
  151. data/lib/karafka/pro/routing/features/multiplexing.rb +5 -5
  152. data/lib/karafka/pro/routing/features/non_blocking_job/topic.rb +3 -3
  153. data/lib/karafka/pro/routing/features/offset_metadata/contracts/topic.rb +2 -4
  154. data/lib/karafka/pro/routing/features/offset_metadata.rb +4 -4
  155. data/lib/karafka/pro/routing/features/parallel_segments/builder.rb +1 -1
  156. data/lib/karafka/pro/routing/features/parallel_segments/contracts/consumer_group.rb +2 -4
  157. data/lib/karafka/pro/routing/features/patterns/contracts/consumer_group.rb +3 -5
  158. data/lib/karafka/pro/routing/features/patterns/contracts/pattern.rb +2 -4
  159. data/lib/karafka/pro/routing/features/patterns/contracts/topic.rb +2 -4
  160. data/lib/karafka/pro/routing/features/patterns/patterns.rb +1 -1
  161. data/lib/karafka/pro/routing/features/pausing/config.rb +26 -0
  162. data/lib/karafka/pro/routing/features/pausing/contracts/topic.rb +17 -11
  163. data/lib/karafka/pro/routing/features/pausing/topic.rb +69 -8
  164. data/lib/karafka/pro/routing/features/periodic_job/contracts/topic.rb +2 -4
  165. data/lib/karafka/pro/routing/features/periodic_job/topic.rb +1 -1
  166. data/lib/karafka/pro/routing/features/recurring_tasks/builder.rb +1 -1
  167. data/lib/karafka/pro/routing/features/recurring_tasks/contracts/topic.rb +2 -4
  168. data/lib/karafka/pro/routing/features/scheduled_messages/contracts/topic.rb +2 -4
  169. data/lib/karafka/pro/routing/features/swarm/contracts/routing.rb +2 -4
  170. data/lib/karafka/pro/routing/features/swarm/contracts/topic.rb +6 -8
  171. data/lib/karafka/pro/routing/features/swarm.rb +1 -1
  172. data/lib/karafka/pro/routing/features/throttling/contracts/topic.rb +2 -4
  173. data/lib/karafka/pro/routing/features/throttling/topic.rb +3 -1
  174. data/lib/karafka/pro/routing/features/virtual_partitions/contracts/topic.rb +2 -4
  175. data/lib/karafka/pro/scheduled_messages/consumer.rb +1 -1
  176. data/lib/karafka/pro/scheduled_messages/contracts/config.rb +4 -6
  177. data/lib/karafka/pro/scheduled_messages/contracts/message.rb +3 -5
  178. data/lib/karafka/pro/scheduled_messages/daily_buffer.rb +3 -2
  179. data/lib/karafka/pro/scheduled_messages/day.rb +1 -0
  180. data/lib/karafka/pro/scheduled_messages/deserializers/headers.rb +1 -1
  181. data/lib/karafka/pro/scheduled_messages/deserializers/payload.rb +1 -1
  182. data/lib/karafka/pro/scheduled_messages/max_epoch.rb +1 -0
  183. data/lib/karafka/pro/scheduled_messages/proxy.rb +1 -1
  184. data/lib/karafka/pro/scheduled_messages/serializer.rb +3 -3
  185. data/lib/karafka/pro/scheduled_messages/setup/config.rb +2 -2
  186. data/lib/karafka/pro/scheduled_messages/state.rb +1 -0
  187. data/lib/karafka/pro/scheduled_messages/tracker.rb +1 -0
  188. data/lib/karafka/pro/scheduled_messages.rb +4 -6
  189. data/lib/karafka/pro/swarm/liveness_listener.rb +2 -2
  190. data/lib/karafka/process.rb +4 -4
  191. data/lib/karafka/processing/coordinator.rb +2 -4
  192. data/lib/karafka/processing/coordinators_buffer.rb +2 -3
  193. data/lib/karafka/processing/executor.rb +3 -4
  194. data/lib/karafka/processing/inline_insights/tracker.rb +1 -0
  195. data/lib/karafka/processing/jobs/base.rb +2 -3
  196. data/lib/karafka/processing/jobs_queue.rb +1 -1
  197. data/lib/karafka/processing/result.rb +1 -0
  198. data/lib/karafka/processing/strategy_selector.rb +1 -0
  199. data/lib/karafka/processing/workers_batch.rb +2 -3
  200. data/lib/karafka/railtie.rb +1 -0
  201. data/lib/karafka/routing/activity_manager.rb +3 -2
  202. data/lib/karafka/routing/builder.rb +8 -8
  203. data/lib/karafka/routing/consumer_group.rb +4 -6
  204. data/lib/karafka/routing/contracts/consumer_group.rb +6 -7
  205. data/lib/karafka/routing/contracts/routing.rb +2 -4
  206. data/lib/karafka/routing/contracts/topic.rb +7 -6
  207. data/lib/karafka/routing/features/active_job/contracts/topic.rb +2 -4
  208. data/lib/karafka/routing/features/active_job/topic.rb +6 -0
  209. data/lib/karafka/routing/features/dead_letter_queue/contracts/topic.rb +3 -5
  210. data/lib/karafka/routing/features/declaratives/contracts/topic.rb +3 -5
  211. data/lib/karafka/routing/features/declaratives/topic.rb +5 -2
  212. data/lib/karafka/routing/features/deserializers/contracts/topic.rb +2 -4
  213. data/lib/karafka/routing/features/deserializers/topic.rb +3 -3
  214. data/lib/karafka/routing/features/eofed/contracts/topic.rb +2 -4
  215. data/lib/karafka/routing/features/inline_insights/contracts/topic.rb +2 -4
  216. data/lib/karafka/routing/features/inline_insights.rb +5 -5
  217. data/lib/karafka/routing/features/manual_offset_management/contracts/topic.rb +2 -4
  218. data/lib/karafka/routing/router.rb +1 -1
  219. data/lib/karafka/routing/subscription_group.rb +1 -1
  220. data/lib/karafka/routing/subscription_groups_builder.rb +1 -0
  221. data/lib/karafka/routing/topic.rb +3 -3
  222. data/lib/karafka/routing/topics.rb +4 -9
  223. data/lib/karafka/server.rb +2 -2
  224. data/lib/karafka/setup/attributes_map.rb +4 -2
  225. data/lib/karafka/setup/config.rb +85 -17
  226. data/lib/karafka/setup/config_proxy.rb +209 -0
  227. data/lib/karafka/setup/contracts/config.rb +13 -11
  228. data/lib/karafka/setup/defaults_injector.rb +3 -2
  229. data/lib/karafka/setup/dsl.rb +2 -3
  230. data/lib/karafka/swarm/liveness_listener.rb +3 -3
  231. data/lib/karafka/swarm/manager.rb +7 -6
  232. data/lib/karafka/swarm/node.rb +1 -1
  233. data/lib/karafka/swarm/supervisor.rb +2 -1
  234. data/lib/karafka/time_trackers/base.rb +1 -1
  235. data/lib/karafka/version.rb +1 -1
  236. data/lib/karafka.rb +4 -4
  237. metadata +14 -6
  238. data/.diffend.yml +0 -3
@@ -0,0 +1,191 @@
1
+ {
2
+ "audience_data_versions": {
3
+ "s1_build_epoch": 1634594595,
4
+ "s2_build_epoch": 1634093288,
5
+ "s3_build_epoch": 1634095356
6
+ },
7
+ "combination_cache_hits": null,
8
+ "content_insertion_info": {
9
+ "ad_rep_account_revenue": {
10
+ "code": "USD",
11
+ "scale": "Nano",
12
+ "value": 0
13
+ },
14
+ "ad_rep_account": {
15
+ "id": "f8a3c7d2-9b41-4e56-a2f3-8d7c1b9e4a6f",
16
+ "name": "AdOps_Beta"
17
+ },
18
+ "advertisement": {
19
+ "duration": {
20
+ "scale": "Micro",
21
+ "value": 29022040
22
+ },
23
+ "external_identifier": null,
24
+ "id": "a9e2f4b7-3c81-4d92-b5e6-7a4f8c2d1e9b",
25
+ "title": "soda",
26
+ "type": "TraditionalAd"
27
+ },
28
+ "platform_revenue": {
29
+ "code": "USD",
30
+ "scale": "Nano",
31
+ "value": 0
32
+ },
33
+ "audience": null,
34
+ "brand": {
35
+ "id": "d4c8e1a9-7f62-4b3d-9e85-c2a7f4b9d1e6",
36
+ "name": "Brand_Beta"
37
+ },
38
+ "campaign": {
39
+ "id": "b7d3a5e8-4c91-4f2b-a6d9-1e8c7f3a5b4d",
40
+ "title": "Pepsi Max",
41
+ "frequency_counting_targets": null
42
+ },
43
+ "campaign_value": {
44
+ "code": "USD",
45
+ "scale": "Nano",
46
+ "value": 500000
47
+ },
48
+ "normalized_campaign_value": {
49
+ "code": "USD",
50
+ "scale": "Nano",
51
+ "value": 500000
52
+ },
53
+ "external_payload_id": "c5e9a2f7-8d41-4b36-9e72-a1f4c8b3d7e5",
54
+ "marker_point": {
55
+ "id": "e2f7c9a4-1d58-4b63-8e49-f7a3c2d8b1e6",
56
+ "episode_version_id": "a8c4e7f2-9b31-4d65-b8a9-e3f7c1d4a2b6",
57
+ "maximum_content_count": 1,
58
+ "maximum_content_duration": {
59
+ "scale": "Micro",
60
+ "value": 120000000
61
+ },
62
+ "position_type": "Preroll",
63
+ "position_sequence": 1
64
+ },
65
+ "position_sequence": 1,
66
+ "series_revenue": {
67
+ "code": "USD",
68
+ "scale": "Nano",
69
+ "value": 0
70
+ }
71
+ },
72
+ "content_insertion_system_type": "ServerSide",
73
+ "count": 1,
74
+ "deduplication_keys": null,
75
+ "distribution_characteristic_id": "c9e3f2a7-4d81-4b56-9e73-a8f2c4d1b7e6",
76
+ "distribution_identification_method_id": "f7a2c8e4-9b31-4d65-8e49-b3f7a1c2d9e8",
77
+ "episode": {
78
+ "created_at": 1698698168000,
79
+ "capacities": [
80
+ {
81
+ "position_type": "Preroll",
82
+ "count": 1,
83
+ "duration": 120
84
+ },
85
+ {
86
+ "position_type": "Midroll",
87
+ "count": 0,
88
+ "duration": 0
89
+ },
90
+ {
91
+ "position_type": "Postroll",
92
+ "count": 0,
93
+ "duration": 0
94
+ }
95
+ ],
96
+ "duration": {
97
+ "scale": "Micro",
98
+ "value": 4204747760
99
+ },
100
+ "episode_number": null,
101
+ "id": "d8e2a7f4-9c51-4b36-a8e2-f7c4d1b9a3e6",
102
+ "title": "Mountain Breeze",
103
+ "episode_version_id": "a8c4e7f2-9b31-4d65-b8a9-e3f7c1d4a2b6"
104
+ },
105
+ "feed": {
106
+ "id": "b4f9c7e2-8a31-4d56-9e82-a7f3c1d4b8e9",
107
+ "type": null
108
+ },
109
+ "feed_item": {
110
+ "id": "d8e2a7f4-9c51-4b36-a8e2-f7c4d1b9a3e6"
111
+ },
112
+ "id": "e7c2f9a4-8d31-4b65-9e78-a3f4c7d2b1e9",
113
+ "listened_at": 1747928515000000,
114
+ "listened_at_ms": 1747928515000,
115
+ "listener": {
116
+ "connection_type": "Cellular",
117
+ "ip_address": "172.58.243.167",
118
+ "ip_address_encryption_format": "None",
119
+ "isp": {
120
+ "as_organization": "WIRELESS-MOBILE",
121
+ "asn": 8445,
122
+ "name": "Random Telecom",
123
+ "organization": "Random Telecom"
124
+ },
125
+ "location": {
126
+ "continent": {
127
+ "code": "NA",
128
+ "geoname_id": 6255149,
129
+ "name": "North America"
130
+ },
131
+ "country": {
132
+ "code": "US",
133
+ "geoname_id": 6252001
134
+ },
135
+ "designated_market_area": {
136
+ "code": "524",
137
+ "name": "Atlanta, GA"
138
+ },
139
+ "is_in_eu": null,
140
+ "locality": {
141
+ "geoname_id": 4180439,
142
+ "name": "Atlanta"
143
+ },
144
+ "region": {
145
+ "geoname_id": 4197000,
146
+ "name": "Georgia"
147
+ },
148
+ "lat": 33.748997,
149
+ "lng": -84.387985,
150
+ "postal_code": "20309"
151
+ },
152
+ "rss_browser": null,
153
+ "time_zone": "America/New_York",
154
+ "user_agent": {
155
+ "browser": "Safari",
156
+ "mobile": true,
157
+ "operating_system": "iOS",
158
+ "platform": null,
159
+ "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1",
160
+ "user_agent_hash": "9k742p/X5m"
161
+ }
162
+ },
163
+ "network": null,
164
+ "playback_group_id": "f9c3e7a2-8d41-4b56-9e73-a8f2c4d1b7e6",
165
+ "request_duration": 0,
166
+ "request_headers": {
167
+ "SERVER_PORT": "80",
168
+ "SERVER_PROTOCOL": "HTTP/1.1",
169
+ "REMOTE_ADDR": "172.58.243.167",
170
+ "ORIGINAL_SCRIPT_NAME": "",
171
+ "HTTP_VERSION": "HTTP/1.1",
172
+ "HTTP_HOST": "foo.bar.com",
173
+ "REQUEST_METHOD": "GET",
174
+ "HTTP_ACCEPT": "*/*",
175
+ "SCRIPT_NAME": "",
176
+ "HTTP_USER_AGENT": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1",
177
+ "REQUEST_PATH": "/paths/d8e2a7f4-9c51-4b36-a8e2-f7c4d1b9a3e6",
178
+ "HTTP_CONNECTION": "close"
179
+ },
180
+ "rejection_status": "NotRejected",
181
+ "root_network": null,
182
+ "season": null,
183
+ "series": {
184
+ "id": "c8e4a7f2-9b31-4d65-8e49-b3f7a1c2d9e8",
185
+ "title": "Podcast"
186
+ },
187
+ "session_id": "a7f2c9e4-8d31-4b56-9e73-a8f4c2d1b7e6",
188
+ "statistics_system": "TwentyFourHourWindows",
189
+ "tracking_id": "b9e3f7a2-4c81-4d56-9e78-a3f4c7d2b1e9",
190
+ "tracking_id_source": "UniqueClientAttributes"
191
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "connect.name": "production.public.automation_actions.Key",
3
+ "fields": [
4
+ {
5
+ "default": "00000000-0000-0000-0000-000000000000",
6
+ "name": "id",
7
+ "type": {
8
+ "connect.default": "00000000-0000-0000-0000-000000000000",
9
+ "connect.name": "io.debezium.data.Uuid",
10
+ "connect.version": 1,
11
+ "type": "string"
12
+ }
13
+ }
14
+ ],
15
+ "name": "Key",
16
+ "namespace": "production.public.automation_actions",
17
+ "type": "record"
18
+ }
@@ -0,0 +1,263 @@
1
+ {
2
+ "connect.name": "production.public.automation_actions.Envelope",
3
+ "connect.version": 1,
4
+ "fields": [
5
+ {
6
+ "default": null,
7
+ "name": "before",
8
+ "type": [
9
+ "null",
10
+ {
11
+ "connect.name": "production.public.automation_actions.Value",
12
+ "fields": [
13
+ {
14
+ "default": "00000000-0000-0000-0000-000000000000",
15
+ "name": "id",
16
+ "type": {
17
+ "connect.default": "00000000-0000-0000-0000-000000000000",
18
+ "connect.name": "io.debezium.data.Uuid",
19
+ "connect.version": 1,
20
+ "type": "string"
21
+ }
22
+ },
23
+ {
24
+ "name": "automation_id",
25
+ "type": "int"
26
+ },
27
+ {
28
+ "default": null,
29
+ "name": "card_id",
30
+ "type": [
31
+ "null",
32
+ "int"
33
+ ]
34
+ },
35
+ {
36
+ "name": "organization_id",
37
+ "type": "int"
38
+ },
39
+ {
40
+ "default": null,
41
+ "name": "user_id",
42
+ "type": [
43
+ "null",
44
+ "int"
45
+ ]
46
+ },
47
+ {
48
+ "name": "action_name",
49
+ "type": "string"
50
+ },
51
+ {
52
+ "default": null,
53
+ "name": "finished_at",
54
+ "type": [
55
+ "null",
56
+ {
57
+ "connect.name": "io.debezium.time.MicroTimestamp",
58
+ "connect.version": 1,
59
+ "type": "long"
60
+ }
61
+ ]
62
+ },
63
+ {
64
+ "default": 0,
65
+ "name": "status",
66
+ "type": [
67
+ {
68
+ "connect.default": 0,
69
+ "type": "int"
70
+ },
71
+ "null"
72
+ ]
73
+ },
74
+ {
75
+ "default": null,
76
+ "name": "deleted_at",
77
+ "type": [
78
+ "null",
79
+ {
80
+ "connect.name": "io.debezium.time.MicroTimestamp",
81
+ "connect.version": 1,
82
+ "type": "long"
83
+ }
84
+ ]
85
+ },
86
+ {
87
+ "name": "created_at",
88
+ "type": {
89
+ "connect.name": "io.debezium.time.MicroTimestamp",
90
+ "connect.version": 1,
91
+ "type": "long"
92
+ }
93
+ },
94
+ {
95
+ "name": "updated_at",
96
+ "type": {
97
+ "connect.name": "io.debezium.time.MicroTimestamp",
98
+ "connect.version": 1,
99
+ "type": "long"
100
+ }
101
+ },
102
+ {
103
+ "default": null,
104
+ "name": "response",
105
+ "type": [
106
+ "null",
107
+ "string"
108
+ ]
109
+ },
110
+ {
111
+ "default": null,
112
+ "name": "executed",
113
+ "type": [
114
+ "null",
115
+ "boolean"
116
+ ]
117
+ }
118
+ ],
119
+ "name": "Value",
120
+ "type": "record"
121
+ }
122
+ ]
123
+ },
124
+ {
125
+ "default": null,
126
+ "name": "after",
127
+ "type": [
128
+ "null",
129
+ "Value"
130
+ ]
131
+ },
132
+ {
133
+ "name": "source",
134
+ "type": {
135
+ "connect.name": "io.debezium.connector.v2.postgresql.Source",
136
+ "fields": [
137
+ {
138
+ "name": "version",
139
+ "type": "string"
140
+ },
141
+ {
142
+ "name": "connector",
143
+ "type": "string"
144
+ },
145
+ {
146
+ "name": "name",
147
+ "type": "string"
148
+ },
149
+ {
150
+ "name": "ts_ms",
151
+ "type": "long"
152
+ },
153
+ {
154
+ "default": "false",
155
+ "name": "snapshot",
156
+ "type": [
157
+ {
158
+ "connect.default": "false",
159
+ "connect.name": "io.debezium.data.Enum",
160
+ "connect.parameters": {
161
+ "allowed": "true,last,false,incremental"
162
+ },
163
+ "connect.version": 1,
164
+ "type": "string"
165
+ },
166
+ "null"
167
+ ]
168
+ },
169
+ {
170
+ "name": "db",
171
+ "type": "string"
172
+ },
173
+ {
174
+ "default": null,
175
+ "name": "sequence",
176
+ "type": [
177
+ "null",
178
+ "string"
179
+ ]
180
+ },
181
+ {
182
+ "name": "schema",
183
+ "type": "string"
184
+ },
185
+ {
186
+ "name": "table",
187
+ "type": "string"
188
+ },
189
+ {
190
+ "default": null,
191
+ "name": "txId",
192
+ "type": [
193
+ "null",
194
+ "long"
195
+ ]
196
+ },
197
+ {
198
+ "default": null,
199
+ "name": "lsn",
200
+ "type": [
201
+ "null",
202
+ "long"
203
+ ]
204
+ },
205
+ {
206
+ "default": null,
207
+ "name": "xmin",
208
+ "type": [
209
+ "null",
210
+ "long"
211
+ ]
212
+ }
213
+ ],
214
+ "name": "Source",
215
+ "namespace": "io.debezium.connector.v2.postgresql",
216
+ "type": "record"
217
+ }
218
+ },
219
+ {
220
+ "name": "op",
221
+ "type": "string"
222
+ },
223
+ {
224
+ "default": null,
225
+ "name": "ts_ms",
226
+ "type": [
227
+ "null",
228
+ "long"
229
+ ]
230
+ },
231
+ {
232
+ "default": null,
233
+ "name": "transaction",
234
+ "type": [
235
+ "null",
236
+ {
237
+ "connect.name": "event.block",
238
+ "connect.version": 1,
239
+ "fields": [
240
+ {
241
+ "name": "id",
242
+ "type": "string"
243
+ },
244
+ {
245
+ "name": "total_order",
246
+ "type": "long"
247
+ },
248
+ {
249
+ "name": "data_collection_order",
250
+ "type": "long"
251
+ }
252
+ ],
253
+ "name": "block",
254
+ "namespace": "event",
255
+ "type": "record"
256
+ }
257
+ ]
258
+ }
259
+ ],
260
+ "name": "Envelope",
261
+ "namespace": "production.public.automation_actions",
262
+ "type": "record"
263
+ }
@@ -0,0 +1,41 @@
1
+ [
2
+ {
3
+ "timestamp": 1111111111111,
4
+ "timestampType": "TYPE",
5
+ "partition": 0,
6
+ "offset": 0,
7
+ "key": "0000000000000000000000000000000000000000000000000000000000000000",
8
+ "value": {
9
+ "id": "0000000000000000000000000000000000000000000000000000000000000000",
10
+ "type": "event_type",
11
+ "data": {
12
+ "user_id": 123456789,
13
+ "user_email": "user@example.com",
14
+ "org_id": 987654321,
15
+ "token_id": 111111111,
16
+ "token_type": "token_type",
17
+ "request_id": "request-id",
18
+ "request_host": "api.example.com",
19
+ "request_path": "/some/path",
20
+ "remote_ip": "0.0.0.0",
21
+ "request_graphql": true,
22
+ "user_agent": "client-library/x.y.z",
23
+ "request_method": "METHOD",
24
+ "graphql_data": {
25
+ "errored": false,
26
+ "complexity": 0,
27
+ "depth": 0,
28
+ "operation_name": null,
29
+ "operation_type": "operation",
30
+ "resources": ["resource"]
31
+ },
32
+ "response_code": "200",
33
+ "type": "custom"
34
+ },
35
+ "source": "some-source",
36
+ "version": 1,
37
+ "timestamp": "1111111111111"
38
+ },
39
+ "headers": []
40
+ }
41
+ ]
data/karafka.gemspec CHANGED
@@ -7,7 +7,7 @@ require 'karafka/version'
7
7
 
8
8
  Gem::Specification.new do |spec|
9
9
  spec.name = 'karafka'
10
- spec.version = ::Karafka::VERSION
10
+ spec.version = Karafka::VERSION
11
11
  spec.platform = Gem::Platform::RUBY
12
12
  spec.authors = ['Maciej Mensfeld']
13
13
  spec.email = %w[contact@karafka.io]
@@ -23,8 +23,8 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_dependency 'base64', '~> 0.2'
25
25
  spec.add_dependency 'karafka-core', '>= 2.5.6', '< 2.6.0'
26
- spec.add_dependency 'karafka-rdkafka', '>= 0.22.0'
27
- spec.add_dependency 'waterdrop', '>= 2.8.9', '< 3.0.0'
26
+ spec.add_dependency 'karafka-rdkafka', '>= 0.23.1'
27
+ spec.add_dependency 'waterdrop', '>= 2.8.14', '< 3.0.0'
28
28
  spec.add_dependency 'zeitwerk', '~> 2.3'
29
29
 
30
30
  spec.required_ruby_version = '>= 3.2.0'
@@ -21,7 +21,7 @@ module ActiveJob
21
21
  # - No Rails: Inherit from Object (standalone ActiveJob usage)
22
22
  #
23
23
  # @see https://github.com/sidekiq/sidekiq/issues/6746 Similar issue in Sidekiq
24
- base = if defined?(Rails) && defined?(Rails::VERSION)
24
+ base = if defined?(Rails::VERSION)
25
25
  (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR < 2 ? Object : AbstractAdapter)
26
26
  else
27
27
  # Fallback when Rails is not loaded
@@ -31,7 +31,7 @@ module ActiveJob
31
31
  # Karafka adapter for enqueuing jobs
32
32
  # This is here for ease of integration with ActiveJob.
33
33
  class KarafkaAdapter < base
34
- include Karafka::Helpers::ConfigImporter.new(
34
+ include ::Karafka::Helpers::ConfigImporter.new(
35
35
  dispatcher: %i[internal active_job dispatcher]
36
36
  )
37
37
 
@@ -67,7 +67,7 @@ module ActiveJob
67
67
 
68
68
  # @return [Boolean] should we stop the job. Used by the ActiveJob continuation feature
69
69
  def stopping?
70
- Karafka::App.done?
70
+ ::Karafka::App.done?
71
71
  end
72
72
  end
73
73
  end
@@ -5,12 +5,16 @@ module Karafka
5
5
  module ActiveJob
6
6
  # This is the consumer for ActiveJob that eats the messages enqueued with it one after another.
7
7
  # It marks the offset after each message, so we make sure, none of the jobs is executed twice
8
- class Consumer < ::Karafka::BaseConsumer
8
+ class Consumer < Karafka::BaseConsumer
9
+ include Helpers::ConfigImporter.new(
10
+ deserializer: %i[internal active_job deserializer]
11
+ )
12
+
9
13
  # Executes the ActiveJob logic
10
14
  # @note ActiveJob does not support batches, so we just run one message after another
11
15
  def consume
12
16
  messages.each do |message|
13
- break if Karafka::App.stopping?
17
+ break if ::Karafka::App.stopping?
14
18
 
15
19
  consume_job(message)
16
20
 
@@ -42,7 +46,7 @@ module Karafka
42
46
  # We technically speaking could set this as deserializer and reference it from the
43
47
  # message instead of using the `#raw_payload`. This is not done on purpose to simplify
44
48
  # the ActiveJob setup here
45
- yield ::ActiveSupport::JSON.decode(job_message.raw_payload)
49
+ yield deserializer.deserialize(job_message)
46
50
  end
47
51
  end
48
52
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module ActiveJob
5
+ module CurrentAttributes
6
+ # Simple wrapper that presents a job hash with current attributes injected.
7
+ #
8
+ # This wrapper exists to pass a modified job hash to the deserializer without
9
+ # modifying the original ActiveJob::Base instance. We cannot modify the job instance
10
+ # directly because:
11
+ #
12
+ # 1. Thread safety: Modifying job instances with singleton methods could cause
13
+ # concurrency issues in multi-threaded environments
14
+ # 2. Rails ownership: ActiveJob::Base is a Rails class we don't control, and
15
+ # monkey-patching it could break with Rails updates
16
+ # 3. Side effects: Modifying the job instance could affect other parts of the
17
+ # application that use the same job object
18
+ #
19
+ # The wrapper implements only the #serialize method that the Deserializer expects,
20
+ # returning our pre-computed hash with current attributes already injected.
21
+ #
22
+ # @example Using JobWrapper with a modified job hash
23
+ # job_hash = {
24
+ # 'job_class' => 'MyJob',
25
+ # 'arguments' => [1, 2, 3],
26
+ # 'cattr_0' => { 'user_id' => 123 }
27
+ # }
28
+ # wrapper = JobWrapper.new(job_hash)
29
+ # wrapper.serialize # => returns the job_hash
30
+ class JobWrapper
31
+ # @param job_hash [Hash] the job hash with current attributes already injected
32
+ def initialize(job_hash)
33
+ @job_hash = job_hash
34
+ end
35
+
36
+ # Returns the job hash with current attributes injected
37
+ #
38
+ # @return [Hash] the job hash with current attributes injected
39
+ def serialize
40
+ @job_hash
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -8,7 +8,7 @@ module Karafka
8
8
  module Loading
9
9
  # @param job_message [Karafka::Messages::Message] message with active job
10
10
  def with_deserialized_job(job_message)
11
- super(job_message) do |job|
11
+ super do |job|
12
12
  resetable = []
13
13
 
14
14
  _cattr_klasses.each do |key, cattr_klass_str|
@@ -4,23 +4,35 @@ module Karafka
4
4
  module ActiveJob
5
5
  module CurrentAttributes
6
6
  # Module adding the current attributes persistence into the ActiveJob jobs
7
+ # This module wraps the Dispatcher#serialize_job to inject current attributes
7
8
  module Persistence
8
- # Alters the job serialization to inject the current attributes into the json before we
9
- # send it to Kafka
9
+ # Wraps the Dispatcher#serialize_job to inject current attributes before serialization
10
+ # This allows us to modify the job before it's serialized without modifying ActiveJob::Base
10
11
  #
11
- # @param job [ActiveJob::Base] job
12
+ # @param job [ActiveJob::Base] the original job to serialize
13
+ # @return [String] serialized job payload with current attributes injected
14
+ #
15
+ # @note This method creates a JobWrapper internally and passes it to the parent's
16
+ # serialize_job method. The wrapper is transparent to the deserializer.
12
17
  def serialize_job(job)
13
- json = super(job)
18
+ # Get the job hash
19
+ job_hash = job.serialize
14
20
 
21
+ # Inject current attributes
15
22
  _cattr_klasses.each do |key, cattr_klass_str|
16
- next if json.key?(key)
23
+ next if job_hash.key?(key)
17
24
 
18
25
  attrs = cattr_klass_str.constantize.attributes
19
26
 
20
- json[key] = attrs unless attrs.empty?
27
+ job_hash[key] = attrs unless attrs.empty?
21
28
  end
22
29
 
23
- json
30
+ # Wrap the modified hash in a simple object that implements #serialize
31
+ # This avoids modifying the original job instance
32
+ wrapper = JobWrapper.new(job_hash)
33
+
34
+ # Pass the wrapper to the deserializer
35
+ super(wrapper)
24
36
  end
25
37
  end
26
38
  end