deimos-ruby 1.8.3 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2badd671866a8fbde743e03acbc2da623279ac08abd5ed983ae9a15a0bef415d
4
- data.tar.gz: e4b3cd2e80b13fc00ff54ebc85b59ab2e1daad052ab170dafd9a75f57eb80ce3
3
+ metadata.gz: 754a19c6aef123b6505a28e4f2f6209a237c02a28b3d7c797b531ead05732c35
4
+ data.tar.gz: bef461f0a501cf3e838135c34c33b746f424ecbfacc99c277e5b16e3d5df74af
5
5
  SHA512:
6
- metadata.gz: 98b41fa7354e624a4538ac5006a091e1a144a2caaa57e2ef77c214e350cd8dcbf2b126c01a3663365d28bbed19baa7525e3c52390cc60f6378537ad8fe6bee12
7
- data.tar.gz: 208ba417a35c7042155383d5c0eb9d9e35be95c0459cf2e58cdc24168c8fdf30af16434fcc66c612d197aab38279d790907f146e19b6a36157cde008c5aa60a3
6
+ metadata.gz: e2496c1de094594c1d1a634f0cfbe14ac755000b748a4010f00705d47f0750411ee0b49e84b87b107419f8df788e5a3a77d09b6467a6d710c1f73538514e6025
7
+ data.tar.gz: 41e6b26586b82b649e5fd8a5b49d52efde0127838e6cda70e81664d9630a16e790e3d5971db4a31273d94030aab5630e5d485af082c08168deb36c659543a81b
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## UNRELEASED
9
9
 
10
+ ## 1.9.0 - 2021-01-28
11
+
12
+ - ### Roadmap :car:
13
+
14
+ - Bumped the version of ruby-kafka to latest
15
+
16
+ - ### Fixes :wrench:
17
+
18
+ - Prevents DB Poller from reconnecting to DB if there is an open transaction
19
+ - Replaces `before` by `prepend_before` for more consistent test setups.
20
+ - Adds validation in the `kafka_producers` method (fixes [#90](https://github.com/flipp-oss/deimos/issues/90))
21
+
22
+ ## 1.8.7 - 2021-01-14
23
+
24
+ - ### Roadmap :car:
25
+ - Update Phobos version to allow version 1.9 or 2.x.
26
+
27
+ ## 1.8.6 - 2021-01-14
28
+
29
+ - ### Fixes :wrench:
30
+ - Fix for configuration bug with Ruby 3.0 (** instead of passing hash)
31
+
32
+ ## 1.8.5 - 2021-01-13
33
+
34
+ - ### Fixes :wrench:
35
+ - Fixes for Rails 6.1 (remove usage of `update_attributes!`)
36
+
37
+ ## 1.8.4 - 2020-12-02
38
+
39
+ ### Features :star:
40
+ - Add overridable "process_message?" method to ActiveRecordConsumer to allow for skipping of saving/updating records
41
+
42
+ ### Fixes :wrench:
43
+
44
+ - Do not apply type coercion to `timestamp-millis` and `timestamp-micros` logical types (fixes [#97](https://github.com/flipp-oss/deimos/issues/97))
45
+
10
46
  ## 1.8.3 - 2020-11-18
11
47
 
12
48
  ### Fixes :wrench:
@@ -15,6 +51,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
15
51
  - KafkaSource crashing on bulk-imports if import hooks are disabled
16
52
  (fixes [#73](https://github.com/flipp-oss/deimos/issues/73))
17
53
  - #96 Use string-safe encoding for partition keys
54
+ - Retry on offset seek failures in inline consumer
55
+ (fixes [#5](Inline consumer should use retries when seeking))
18
56
 
19
57
  ## 1.8.2 - 2020-09-25
20
58
 
@@ -1,73 +1,77 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- deimos-ruby (1.8.2)
4
+ deimos-ruby (1.8.7)
5
5
  avro_turf (~> 0.11)
6
- phobos (~> 1.9)
7
- ruby-kafka (~> 0.7)
6
+ phobos (>= 1.9, < 3.0)
7
+ ruby-kafka (< 2)
8
8
  sigurd (= 0.0.1)
9
9
 
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
- actioncable (6.0.3.2)
14
- actionpack (= 6.0.3.2)
13
+ actioncable (6.1.1)
14
+ actionpack (= 6.1.1)
15
+ activesupport (= 6.1.1)
15
16
  nio4r (~> 2.0)
16
17
  websocket-driver (>= 0.6.1)
17
- actionmailbox (6.0.3.2)
18
- actionpack (= 6.0.3.2)
19
- activejob (= 6.0.3.2)
20
- activerecord (= 6.0.3.2)
21
- activestorage (= 6.0.3.2)
22
- activesupport (= 6.0.3.2)
18
+ actionmailbox (6.1.1)
19
+ actionpack (= 6.1.1)
20
+ activejob (= 6.1.1)
21
+ activerecord (= 6.1.1)
22
+ activestorage (= 6.1.1)
23
+ activesupport (= 6.1.1)
23
24
  mail (>= 2.7.1)
24
- actionmailer (6.0.3.2)
25
- actionpack (= 6.0.3.2)
26
- actionview (= 6.0.3.2)
27
- activejob (= 6.0.3.2)
25
+ actionmailer (6.1.1)
26
+ actionpack (= 6.1.1)
27
+ actionview (= 6.1.1)
28
+ activejob (= 6.1.1)
29
+ activesupport (= 6.1.1)
28
30
  mail (~> 2.5, >= 2.5.4)
29
31
  rails-dom-testing (~> 2.0)
30
- actionpack (6.0.3.2)
31
- actionview (= 6.0.3.2)
32
- activesupport (= 6.0.3.2)
33
- rack (~> 2.0, >= 2.0.8)
32
+ actionpack (6.1.1)
33
+ actionview (= 6.1.1)
34
+ activesupport (= 6.1.1)
35
+ rack (~> 2.0, >= 2.0.9)
34
36
  rack-test (>= 0.6.3)
35
37
  rails-dom-testing (~> 2.0)
36
38
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
37
- actiontext (6.0.3.2)
38
- actionpack (= 6.0.3.2)
39
- activerecord (= 6.0.3.2)
40
- activestorage (= 6.0.3.2)
41
- activesupport (= 6.0.3.2)
39
+ actiontext (6.1.1)
40
+ actionpack (= 6.1.1)
41
+ activerecord (= 6.1.1)
42
+ activestorage (= 6.1.1)
43
+ activesupport (= 6.1.1)
42
44
  nokogiri (>= 1.8.5)
43
- actionview (6.0.3.2)
44
- activesupport (= 6.0.3.2)
45
+ actionview (6.1.1)
46
+ activesupport (= 6.1.1)
45
47
  builder (~> 3.1)
46
48
  erubi (~> 1.4)
47
49
  rails-dom-testing (~> 2.0)
48
50
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
49
- activejob (6.0.3.2)
50
- activesupport (= 6.0.3.2)
51
+ activejob (6.1.1)
52
+ activesupport (= 6.1.1)
51
53
  globalid (>= 0.3.6)
52
- activemodel (6.0.3.2)
53
- activesupport (= 6.0.3.2)
54
- activerecord (6.0.3.2)
55
- activemodel (= 6.0.3.2)
56
- activesupport (= 6.0.3.2)
57
- activerecord-import (1.0.5)
54
+ activemodel (6.1.1)
55
+ activesupport (= 6.1.1)
56
+ activerecord (6.1.1)
57
+ activemodel (= 6.1.1)
58
+ activesupport (= 6.1.1)
59
+ activerecord-import (1.0.7)
58
60
  activerecord (>= 3.2)
59
- activestorage (6.0.3.2)
60
- actionpack (= 6.0.3.2)
61
- activejob (= 6.0.3.2)
62
- activerecord (= 6.0.3.2)
61
+ activestorage (6.1.1)
62
+ actionpack (= 6.1.1)
63
+ activejob (= 6.1.1)
64
+ activerecord (= 6.1.1)
65
+ activesupport (= 6.1.1)
63
66
  marcel (~> 0.3.1)
64
- activesupport (6.0.3.2)
67
+ mimemagic (~> 0.3.2)
68
+ activesupport (6.1.1)
65
69
  concurrent-ruby (~> 1.0, >= 1.0.2)
66
- i18n (>= 0.7, < 2)
67
- minitest (~> 5.1)
68
- tzinfo (~> 1.1)
69
- zeitwerk (~> 2.2, >= 2.2.2)
70
- ast (2.4.1)
70
+ i18n (>= 1.6, < 2)
71
+ minitest (>= 5.1)
72
+ tzinfo (~> 2.0)
73
+ zeitwerk (~> 2.3)
74
+ ast (2.4.2)
71
75
  avro (1.9.2)
72
76
  multi_json
73
77
  avro_turf (0.11.0)
@@ -75,21 +79,21 @@ GEM
75
79
  excon (~> 0.45)
76
80
  builder (3.2.4)
77
81
  coderay (1.1.3)
78
- concurrent-ruby (1.1.6)
79
- concurrent-ruby-ext (1.1.6)
80
- concurrent-ruby (= 1.1.6)
82
+ concurrent-ruby (1.1.8)
83
+ concurrent-ruby-ext (1.1.8)
84
+ concurrent-ruby (= 1.1.8)
81
85
  crass (1.0.6)
82
86
  database_cleaner (1.8.5)
83
- ddtrace (0.37.0)
87
+ ddtrace (0.45.0)
84
88
  msgpack
85
89
  diff-lcs (1.4.4)
86
- digest-crc (0.6.1)
87
- rake (~> 13.0)
88
- dogstatsd-ruby (4.8.1)
89
- erubi (1.9.0)
90
- excon (0.76.0)
90
+ digest-crc (0.6.3)
91
+ rake (>= 12.0.0, < 14.0.0)
92
+ dogstatsd-ruby (4.8.2)
93
+ erubi (1.10.0)
94
+ excon (0.78.1)
91
95
  exponential-backoff (0.0.4)
92
- ffi (1.13.1)
96
+ ffi (1.14.2)
93
97
  formatador (0.2.5)
94
98
  globalid (0.4.2)
95
99
  activesupport (>= 4.2.0)
@@ -107,22 +111,22 @@ GEM
107
111
  guard (~> 2.1)
108
112
  guard-compat (~> 1.1)
109
113
  rspec (>= 2.99.0, < 4.0)
110
- guard-rubocop (1.3.0)
114
+ guard-rubocop (1.4.0)
111
115
  guard (~> 2.0)
112
- rubocop (~> 0.20)
113
- i18n (1.8.4)
116
+ rubocop (< 2.0)
117
+ i18n (1.8.7)
114
118
  concurrent-ruby (~> 1.0)
115
- listen (3.2.1)
119
+ listen (3.4.1)
116
120
  rb-fsevent (~> 0.10, >= 0.10.3)
117
121
  rb-inotify (~> 0.9, >= 0.9.10)
118
122
  little-plugger (1.1.4)
119
123
  logging (2.3.0)
120
124
  little-plugger (~> 1.1)
121
125
  multi_json (~> 1.14)
122
- loofah (2.6.0)
126
+ loofah (2.9.0)
123
127
  crass (~> 1.0.2)
124
128
  nokogiri (>= 1.5.9)
125
- lumberjack (1.2.6)
129
+ lumberjack (1.2.8)
126
130
  mail (2.7.1)
127
131
  mini_mime (>= 0.1.1)
128
132
  marcel (0.3.3)
@@ -130,23 +134,24 @@ GEM
130
134
  method_source (1.0.0)
131
135
  mimemagic (0.3.5)
132
136
  mini_mime (1.0.2)
133
- mini_portile2 (2.4.0)
134
- minitest (5.14.1)
135
- msgpack (1.3.3)
137
+ mini_portile2 (2.5.0)
138
+ minitest (5.14.3)
139
+ msgpack (1.4.1)
136
140
  multi_json (1.15.0)
137
141
  mysql2 (0.5.3)
138
142
  nenv (0.3.0)
139
- nio4r (2.5.2)
140
- nokogiri (1.10.10)
141
- mini_portile2 (~> 2.4.0)
143
+ nio4r (2.5.4)
144
+ nokogiri (1.11.1)
145
+ mini_portile2 (~> 2.5.0)
146
+ racc (~> 1.4)
142
147
  notiffany (0.1.3)
143
148
  nenv (~> 0.1)
144
149
  shellany (~> 0.0)
145
- parallel (1.19.2)
146
- parser (2.7.1.4)
150
+ parallel (1.20.1)
151
+ parser (3.0.0.0)
147
152
  ast (~> 2.4.1)
148
153
  pg (1.2.3)
149
- phobos (1.9.0)
154
+ phobos (2.0.2)
150
155
  activesupport (>= 3.0.0)
151
156
  concurrent-ruby (>= 1.0.2)
152
157
  concurrent-ruby-ext (>= 1.0.2)
@@ -157,63 +162,64 @@ GEM
157
162
  pry (0.13.1)
158
163
  coderay (~> 1.1)
159
164
  method_source (~> 1.0)
165
+ racc (1.5.2)
160
166
  rack (2.2.3)
161
167
  rack-test (1.1.0)
162
168
  rack (>= 1.0, < 3)
163
- rails (6.0.3.2)
164
- actioncable (= 6.0.3.2)
165
- actionmailbox (= 6.0.3.2)
166
- actionmailer (= 6.0.3.2)
167
- actionpack (= 6.0.3.2)
168
- actiontext (= 6.0.3.2)
169
- actionview (= 6.0.3.2)
170
- activejob (= 6.0.3.2)
171
- activemodel (= 6.0.3.2)
172
- activerecord (= 6.0.3.2)
173
- activestorage (= 6.0.3.2)
174
- activesupport (= 6.0.3.2)
175
- bundler (>= 1.3.0)
176
- railties (= 6.0.3.2)
169
+ rails (6.1.1)
170
+ actioncable (= 6.1.1)
171
+ actionmailbox (= 6.1.1)
172
+ actionmailer (= 6.1.1)
173
+ actionpack (= 6.1.1)
174
+ actiontext (= 6.1.1)
175
+ actionview (= 6.1.1)
176
+ activejob (= 6.1.1)
177
+ activemodel (= 6.1.1)
178
+ activerecord (= 6.1.1)
179
+ activestorage (= 6.1.1)
180
+ activesupport (= 6.1.1)
181
+ bundler (>= 1.15.0)
182
+ railties (= 6.1.1)
177
183
  sprockets-rails (>= 2.0.0)
178
184
  rails-dom-testing (2.0.3)
179
185
  activesupport (>= 4.2.0)
180
186
  nokogiri (>= 1.6)
181
187
  rails-html-sanitizer (1.3.0)
182
188
  loofah (~> 2.3)
183
- railties (6.0.3.2)
184
- actionpack (= 6.0.3.2)
185
- activesupport (= 6.0.3.2)
189
+ railties (6.1.1)
190
+ actionpack (= 6.1.1)
191
+ activesupport (= 6.1.1)
186
192
  method_source
187
193
  rake (>= 0.8.7)
188
- thor (>= 0.20.3, < 2.0)
194
+ thor (~> 1.0)
189
195
  rainbow (3.0.0)
190
- rake (13.0.1)
196
+ rake (13.0.3)
191
197
  rb-fsevent (0.10.4)
192
198
  rb-inotify (0.10.1)
193
199
  ffi (~> 1.0)
194
- regexp_parser (1.7.1)
200
+ regexp_parser (2.0.3)
195
201
  rexml (3.2.4)
196
- rspec (3.9.0)
197
- rspec-core (~> 3.9.0)
198
- rspec-expectations (~> 3.9.0)
199
- rspec-mocks (~> 3.9.0)
200
- rspec-core (3.9.2)
201
- rspec-support (~> 3.9.3)
202
- rspec-expectations (3.9.2)
202
+ rspec (3.10.0)
203
+ rspec-core (~> 3.10.0)
204
+ rspec-expectations (~> 3.10.0)
205
+ rspec-mocks (~> 3.10.0)
206
+ rspec-core (3.10.1)
207
+ rspec-support (~> 3.10.0)
208
+ rspec-expectations (3.10.1)
203
209
  diff-lcs (>= 1.2.0, < 2.0)
204
- rspec-support (~> 3.9.0)
205
- rspec-mocks (3.9.1)
210
+ rspec-support (~> 3.10.0)
211
+ rspec-mocks (3.10.1)
206
212
  diff-lcs (>= 1.2.0, < 2.0)
207
- rspec-support (~> 3.9.0)
208
- rspec-rails (4.0.1)
213
+ rspec-support (~> 3.10.0)
214
+ rspec-rails (4.0.2)
209
215
  actionpack (>= 4.2)
210
216
  activesupport (>= 4.2)
211
217
  railties (>= 4.2)
212
- rspec-core (~> 3.9)
213
- rspec-expectations (~> 3.9)
214
- rspec-mocks (~> 3.9)
215
- rspec-support (~> 3.9)
216
- rspec-support (3.9.3)
218
+ rspec-core (~> 3.10)
219
+ rspec-expectations (~> 3.10)
220
+ rspec-mocks (~> 3.10)
221
+ rspec-support (~> 3.10)
222
+ rspec-support (3.10.1)
217
223
  rspec_junit_formatter (0.4.1)
218
224
  rspec-core (>= 2, < 4, != 2.12.0)
219
225
  rubocop (0.88.0)
@@ -225,13 +231,13 @@ GEM
225
231
  rubocop-ast (>= 0.1.0, < 1.0)
226
232
  ruby-progressbar (~> 1.7)
227
233
  unicode-display_width (>= 1.4.0, < 2.0)
228
- rubocop-ast (0.2.0)
229
- parser (>= 2.7.0.1)
234
+ rubocop-ast (0.8.0)
235
+ parser (>= 2.7.1.5)
230
236
  rubocop-rspec (1.42.0)
231
237
  rubocop (>= 0.87.0)
232
- ruby-kafka (0.7.10)
238
+ ruby-kafka (1.3.0)
233
239
  digest-crc
234
- ruby-progressbar (1.10.1)
240
+ ruby-progressbar (1.11.0)
235
241
  shellany (0.0.1)
236
242
  sigurd (0.0.1)
237
243
  concurrent-ruby (~> 1)
@@ -239,20 +245,19 @@ GEM
239
245
  sprockets (4.0.2)
240
246
  concurrent-ruby (~> 1.0)
241
247
  rack (> 1, < 3)
242
- sprockets-rails (3.2.1)
248
+ sprockets-rails (3.2.2)
243
249
  actionpack (>= 4.0)
244
250
  activesupport (>= 4.0)
245
251
  sprockets (>= 3.0.0)
246
252
  sqlite3 (1.4.2)
247
- thor (1.0.1)
248
- thread_safe (0.3.6)
249
- tzinfo (1.2.7)
250
- thread_safe (~> 0.1)
253
+ thor (1.1.0)
254
+ tzinfo (2.0.4)
255
+ concurrent-ruby (~> 1.0)
251
256
  unicode-display_width (1.7.0)
252
257
  websocket-driver (0.7.3)
253
258
  websocket-extensions (>= 0.1.0)
254
259
  websocket-extensions (0.1.5)
255
- zeitwerk (2.4.0)
260
+ zeitwerk (2.4.2)
256
261
 
257
262
  PLATFORMS
258
263
  ruby
@@ -274,9 +279,9 @@ DEPENDENCIES
274
279
  rspec (~> 3)
275
280
  rspec-rails (~> 4)
276
281
  rspec_junit_formatter (~> 0.3)
277
- rubocop (~> 0.72)
278
- rubocop-rspec (~> 1.27)
282
+ rubocop (= 0.88.0)
283
+ rubocop-rspec (= 1.42.0)
279
284
  sqlite3 (~> 1.3)
280
285
 
281
286
  BUNDLED WITH
282
- 2.1.4
287
+ 2.2.5
data/README.md CHANGED
@@ -626,6 +626,15 @@ class MyConsumer < Deimos::ActiveRecordConsumer
626
626
  def record_key(payload)
627
627
  super
628
628
  end
629
+
630
+ # Optional override, returns true by default.
631
+ # When this method returns true, a record corresponding to the message
632
+ # is created/updated.
633
+ # When this method returns false, message processing is skipped and a
634
+ # corresponding record will NOT be created/updated.
635
+ def process_message?(payload)
636
+ super
637
+ end
629
638
  end
630
639
  ```
631
640
 
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_runtime_dependency('avro_turf', '~> 0.11')
22
- spec.add_runtime_dependency('phobos', '~> 1.9')
23
- spec.add_runtime_dependency('ruby-kafka', '~> 0.7')
22
+ spec.add_runtime_dependency('phobos', '>= 1.9', '< 3.0')
23
+ spec.add_runtime_dependency('ruby-kafka', '< 2')
24
24
  spec.add_runtime_dependency('sigurd', '0.0.1')
25
25
 
26
26
  spec.add_development_dependency('activerecord-import')
@@ -38,7 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency('rspec', '~> 3')
39
39
  spec.add_development_dependency('rspec_junit_formatter', '~>0.3')
40
40
  spec.add_development_dependency('rspec-rails', '~> 4')
41
- spec.add_development_dependency('rubocop', '~> 0.72')
42
- spec.add_development_dependency('rubocop-rspec', '~> 1.27')
41
+ spec.add_development_dependency('rubocop', '0.88.0')
42
+ spec.add_development_dependency('rubocop-rspec', '1.42.0')
43
43
  spec.add_development_dependency('sqlite3', '~> 1.3')
44
44
  end
@@ -28,6 +28,7 @@ Please describe the tests that you ran to verify your changes. Provide instructi
28
28
  - [ ] I have performed a self-review of my own code
29
29
  - [ ] I have commented my code, particularly in hard-to-understand areas
30
30
  - [ ] I have made corresponding changes to the documentation
31
+ - [ ] I have added a line in the CHANGELOG describing this change, under the UNRELEASED heading
31
32
  - [ ] My changes generate no new warnings
32
33
  - [ ] I have added tests that prove my fix is effective or that my feature works
33
34
  - [ ] New and existing unit tests pass locally with my changes
@@ -26,6 +26,15 @@ module Deimos
26
26
 
27
27
  # :nodoc:
28
28
  def consume(payload, metadata)
29
+ unless self.process_message?(payload)
30
+ Deimos.config.logger.debug(
31
+ message: 'Skipping processing of message',
32
+ payload: payload,
33
+ metadata: metadata
34
+ )
35
+ return
36
+ end
37
+
29
38
  key = metadata.with_indifferent_access[:key]
30
39
  klass = self.class.config[:record_class]
31
40
  record = fetch_record(klass, (payload || {}).with_indifferent_access, key)
@@ -55,5 +55,13 @@ module Deimos
55
55
  def record_attributes(payload, _key=nil)
56
56
  @converter.convert(payload)
57
57
  end
58
+
59
+ # Override this message to conditionally save records
60
+ # @param payload [Hash] The kafka message as a hash
61
+ # @return [Boolean] if true, record is created/update.
62
+ # If false, record processing is skipped but message offset is still committed.
63
+ def process_message?(_payload)
64
+ true
65
+ end
58
66
  end
59
67
  end
@@ -67,7 +67,7 @@ module Deimos
67
67
  topic(kafka_config.topic) if kafka_config.topic.present? && klass.respond_to?(:topic)
68
68
  schema(kafka_config.schema) if kafka_config.schema.present?
69
69
  namespace(kafka_config.namespace) if kafka_config.namespace.present?
70
- key_config(kafka_config.key_config) if kafka_config.key_config.present?
70
+ key_config(**kafka_config.key_config) if kafka_config.key_config.present?
71
71
  end
72
72
  end
73
73
 
@@ -6,6 +6,9 @@ module Deimos
6
6
  module KafkaSource
7
7
  extend ActiveSupport::Concern
8
8
 
9
+ DEPRECATION_WARNING = 'The kafka_producer interface will be deprecated ' \
10
+ 'in future releases. Please use kafka_producers instead.'
11
+
9
12
  included do
10
13
  after_create(:send_kafka_event_on_create)
11
14
  after_update(:send_kafka_event_on_update)
@@ -64,19 +67,12 @@ module Deimos
64
67
 
65
68
  # @return [Array<Deimos::ActiveRecordProducer>] the producers to run.
66
69
  def kafka_producers
67
- raise NotImplementedError if self.method(:kafka_producer).
68
- owner == Deimos::KafkaSource
69
-
70
- [self.kafka_producer]
71
- end
72
-
73
- # Deprecated - use #kafka_producers instead.
74
- # @return [Deimos::ActiveRecordProducer] the producer to use.
75
- def kafka_producer
76
- raise NotImplementedError if self.method(:kafka_producers).
77
- owner == Deimos::KafkaSource
70
+ if self.respond_to?(:kafka_producer)
71
+ Deimos.config.logger.warn(message: DEPRECATION_WARNING)
72
+ return [self.kafka_producer]
73
+ end
78
74
 
79
- self.kafka_producers.first
75
+ raise NotImplementedError
80
76
  end
81
77
 
82
78
  # This is an internal method, part of the activerecord_import gem. It's
@@ -85,11 +85,8 @@ module Deimos
85
85
  locked_at: Time.zone.now,
86
86
  error: true,
87
87
  retries: record.retries + 1 }
88
- if ActiveRecord::VERSION::MAJOR >= 4
89
- record.update!(attr_hash)
90
- else
91
- record.update_attributes!(attr_hash)
92
- end
88
+ record.attributes = attr_hash
89
+ record.save!
93
90
  end
94
91
 
95
92
  # Update the locked_at timestamp to indicate that the producer is still
@@ -44,9 +44,11 @@ module Deimos
44
44
 
45
45
  case field_type
46
46
  when :int, :long
47
- if val.is_a?(Integer) ||
48
- _is_integer_string?(val) ||
49
- int_classes.any? { |klass| val.is_a?(klass) }
47
+ if %w(timestamp-millis timestamp-micros).include?(type.logical_type)
48
+ val
49
+ elsif val.is_a?(Integer) ||
50
+ _is_integer_string?(val) ||
51
+ int_classes.any? { |klass| val.is_a?(klass) }
50
52
  val.to_i
51
53
  else
52
54
  val # this will fail
@@ -34,7 +34,7 @@ module Deimos
34
34
  end
35
35
  end
36
36
 
37
- config.before(:each) do
37
+ config.prepend_before(:each) do
38
38
  client = double('client').as_null_object
39
39
  allow(client).to receive(:time) do |*_args, &block|
40
40
  block.call
@@ -68,7 +68,7 @@ module Deimos
68
68
 
69
69
  # Grab the PollInfo or create if it doesn't exist.
70
70
  def retrieve_poll_info
71
- ActiveRecord::Base.connection.reconnect!
71
+ ActiveRecord::Base.connection.reconnect! unless ActiveRecord::Base.connection.open_transactions.positive?
72
72
  new_time = @config.start_from_beginning ? Time.new(0) : Time.zone.now
73
73
  @info = Deimos::PollInfo.find_by_producer(@config.producer_class) ||
74
74
  Deimos::PollInfo.create!(producer: @config.producer_class,
@@ -142,7 +142,8 @@ module Deimos
142
142
  last_id = record.public_send(id_method)
143
143
  last_updated_at = last_updated(record)
144
144
  @producer.send_events(batch)
145
- @info.update_attributes!(last_sent: last_updated_at, last_sent_id: last_id)
145
+ @info.attributes = { last_sent: last_updated_at, last_sent_id: last_id }
146
+ @info.save!
146
147
  end
147
148
  end
148
149
  end
@@ -6,6 +6,7 @@ module Deimos
6
6
  module Utils
7
7
  # Listener that can seek to get the last X messages in a topic.
8
8
  class SeekListener < Phobos::Listener
9
+ MAX_SEEK_RETRIES = 3
9
10
  attr_accessor :num_messages
10
11
 
11
12
  # :nodoc:
@@ -13,8 +14,10 @@ module Deimos
13
14
  @num_messages ||= 10
14
15
  @consumer = create_kafka_consumer
15
16
  @consumer.subscribe(topic, @subscribe_opts)
17
+ attempt = 0
16
18
 
17
19
  begin
20
+ attempt += 1
18
21
  last_offset = @kafka_client.last_offset_for(topic, 0)
19
22
  offset = last_offset - num_messages
20
23
  if offset.positive?
@@ -22,7 +25,11 @@ module Deimos
22
25
  @consumer.seek(topic, 0, offset)
23
26
  end
24
27
  rescue StandardError => e
25
- "Could not seek to offset: #{e.message}"
28
+ if attempt < MAX_SEEK_RETRIES
29
+ sleep(1.seconds * attempt)
30
+ retry
31
+ end
32
+ log_error("Could not seek to offset: #{e.message} after #{MAX_SEEK_RETRIES} retries", listener_metadata)
26
33
  end
27
34
 
28
35
  instrument('listener.start_handler', listener_metadata) do
@@ -50,7 +57,6 @@ module Deimos
50
57
 
51
58
  # :nodoc:
52
59
  def consume(payload, metadata)
53
- puts "Got #{payload}"
54
60
  self.class.total_messages << {
55
61
  key: metadata[:key],
56
62
  payload: payload
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Deimos
4
- VERSION = '1.8.3'
4
+ VERSION = '1.9.0'
5
5
  end
@@ -137,5 +137,18 @@ module ActiveRecordConsumerTest
137
137
  expect(Widget.find_by_test_id('id1').some_int).to eq(3)
138
138
  expect(Widget.find_by_test_id('id2').some_int).to eq(4)
139
139
  end
140
+
141
+ it 'should not create record of process_message returns false' do
142
+ MyConsumer.any_instance.stub(:process_message?).and_return(false)
143
+ expect(Widget.count).to eq(0)
144
+ test_consume_message(MyConsumer, {
145
+ test_id: 'abc',
146
+ some_int: 3,
147
+ updated_at: 1.day.ago.to_i,
148
+ some_datetime_int: Time.zone.now.to_i,
149
+ timestamp: 2.minutes.ago.to_s
150
+ }, { call_original: true, key: 5 })
151
+ expect(Widget.count).to eq(0)
152
+ end
140
153
  end
141
154
  end
@@ -16,7 +16,7 @@ RSpec.describe Deimos::Generators::ActiveRecordGenerator do
16
16
  files = Dir['db/migrate/*.rb']
17
17
  expect(files.length).to eq(1)
18
18
  results = <<~MIGRATION
19
- class CreateGeneratedTable < ActiveRecord::Migration[6.0]
19
+ class CreateGeneratedTable < ActiveRecord::Migration[6.1]
20
20
  def up
21
21
  if table_exists?(:generated_table)
22
22
  warn "generated_table already exists, exiting"
@@ -308,5 +308,74 @@ module KafkaSourceSpec
308
308
  }, widgets[1].id)
309
309
  end
310
310
  end
311
+
312
+ context 'with AR models that implement the kafka_producer interface' do
313
+ before(:each) do
314
+ # Dummy class we can include the mixin in. Has a backing table created
315
+ # earlier and has the import hook disabled
316
+ deprecated_class = Class.new(ActiveRecord::Base) do
317
+ include Deimos::KafkaSource
318
+ self.table_name = 'widgets'
319
+
320
+ # :nodoc:
321
+ def self.kafka_config
322
+ {
323
+ update: true,
324
+ delete: true,
325
+ import: false,
326
+ create: true
327
+ }
328
+ end
329
+
330
+ # :nodoc:
331
+ def self.kafka_producer
332
+ WidgetProducer
333
+ end
334
+ end
335
+ stub_const('WidgetDeprecated', deprecated_class)
336
+ WidgetDeprecated.reset_column_information
337
+ end
338
+
339
+ it 'logs a warning and sends the message as usual' do
340
+ expect(Deimos.config.logger).to receive(:warn).with({ message: WidgetDeprecated::DEPRECATION_WARNING })
341
+ widget = WidgetDeprecated.create(widget_id: 1, name: 'Widget 1')
342
+ expect('my-topic').to have_sent({
343
+ widget_id: 1,
344
+ name: 'Widget 1',
345
+ id: widget.id,
346
+ created_at: anything,
347
+ updated_at: anything
348
+ }, widget.id)
349
+ end
350
+ end
351
+
352
+ context 'with AR models that do not implement any producer interface' do
353
+ before(:each) do
354
+ # Dummy class we can include the mixin in. Has a backing table created
355
+ # earlier and has the import hook disabled
356
+ buggy_class = Class.new(ActiveRecord::Base) do
357
+ include Deimos::KafkaSource
358
+ self.table_name = 'widgets'
359
+
360
+ # :nodoc:
361
+ def self.kafka_config
362
+ {
363
+ update: true,
364
+ delete: true,
365
+ import: false,
366
+ create: true
367
+ }
368
+ end
369
+ end
370
+ stub_const('WidgetBuggy', buggy_class)
371
+ WidgetBuggy.reset_column_information
372
+ end
373
+
374
+ it 'raises a NotImplementedError exception' do
375
+ expect {
376
+ WidgetBuggy.create(widget_id: 1, name: 'Widget 1')
377
+ }.to raise_error(NotImplementedError)
378
+ end
379
+ end
311
380
  end
312
381
  end
@@ -51,13 +51,13 @@ each_db_config(Deimos::KafkaTopicInfo) do
51
51
  expect(record.locked_at).to eq(nil)
52
52
  expect(record.error).to eq(false)
53
53
  expect(record.retries).to eq(0)
54
- expect(record.last_processed_at.to_s).to eq(Time.zone.now.to_s)
54
+ expect(record.last_processed_at.in_time_zone.to_s).to eq(Time.zone.now.to_s)
55
55
  record = Deimos::KafkaTopicInfo.last
56
56
  expect(record.locked_by).not_to eq(nil)
57
57
  expect(record.locked_at).not_to eq(nil)
58
58
  expect(record.error).not_to eq(false)
59
59
  expect(record.retries).not_to eq(0)
60
- expect(record.last_processed_at.to_s).to eq(20.seconds.ago.to_s)
60
+ expect(record.last_processed_at.in_time_zone.to_s).to eq(20.seconds.ago.to_s)
61
61
  end
62
62
  end
63
63
 
@@ -70,11 +70,11 @@ each_db_config(Deimos::KafkaTopicInfo) do
70
70
  locked_by: 'me', locked_at: 1.minute.ago)
71
71
 
72
72
  expect(Deimos::KafkaTopicInfo.count).to eq(3)
73
- Deimos::KafkaTopicInfo.all.each { |t| expect(t.last_processed_at.to_s).to eq(old_time) }
73
+ Deimos::KafkaTopicInfo.all.each { |t| expect(t.last_processed_at.in_time_zone.to_s).to eq(old_time) }
74
74
  Deimos::KafkaTopicInfo.ping_empty_topics(%w(topic1))
75
- expect(t1.reload.last_processed_at.to_s).to eq(old_time) # was passed as an exception
76
- expect(t2.reload.last_processed_at.to_s).to eq(Time.zone.now.to_s)
77
- expect(t3.reload.last_processed_at.to_s).to eq(old_time) # is locked
75
+ expect(t1.reload.last_processed_at.in_time_zone.to_s).to eq(old_time) # was passed as an exception
76
+ expect(t2.reload.last_processed_at.in_time_zone.to_s).to eq(Time.zone.now.to_s)
77
+ expect(t3.reload.last_processed_at.in_time_zone.to_s).to eq(old_time) # is locked
78
78
  end
79
79
  end
80
80
 
@@ -42,6 +42,20 @@ RSpec.shared_examples_for('an Avro backend') do
42
42
  {
43
43
  'name' => 'union-int-field',
44
44
  'type' => %w(null int)
45
+ },
46
+ {
47
+ 'name' => 'timestamp-millis-field',
48
+ 'type' => {
49
+ 'type' => 'long',
50
+ 'logicalType' => 'timestamp-millis'
51
+ }
52
+ },
53
+ {
54
+ 'name' => 'timestamp-micros-field',
55
+ 'type' => {
56
+ 'type' => 'long',
57
+ 'logicalType' => 'timestamp-micros'
58
+ }
45
59
  }
46
60
  ]
47
61
  }
@@ -95,7 +109,9 @@ RSpec.shared_examples_for('an Avro backend') do
95
109
  'string-field' => 'hi mom',
96
110
  'boolean-field' => true,
97
111
  'union-field' => nil,
98
- 'union-int-field' => nil
112
+ 'union-int-field' => nil,
113
+ 'timestamp-millis-field' => Time.utc(2020, 11, 12, 13, 14, 15, 909_090),
114
+ 'timestamp-micros-field' => Time.utc(2020, 11, 12, 13, 14, 15, 909_090)
99
115
  }
100
116
  end
101
117
 
@@ -169,6 +185,15 @@ RSpec.shared_examples_for('an Avro backend') do
169
185
  expect(result['union-field']).to eq('itsme')
170
186
  end
171
187
 
188
+ it 'should not convert timestamp-millis' do
189
+ result = backend.coerce(payload)
190
+ expect(result['timestamp-millis-field']).to eq(Time.utc(2020, 11, 12, 13, 14, 15, 909_090))
191
+ end
192
+
193
+ it 'should not convert timestamp-micros' do
194
+ result = backend.coerce(payload)
195
+ expect(result['timestamp-micros-field']).to eq(Time.utc(2020, 11, 12, 13, 14, 15, 909_090))
196
+ end
172
197
  end
173
198
 
174
199
  end
@@ -87,7 +87,7 @@ module DbConfigs
87
87
  port: 3306,
88
88
  username: 'root',
89
89
  database: 'test',
90
- host: ENV['MYSQL_HOST'] || 'localhost'
90
+ host: ENV['MYSQL_HOST'] || '127.0.0.1'
91
91
  },
92
92
  {
93
93
  adapter: 'sqlite3',
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Deimos::Utils::SeekListener do
4
+
5
+ describe '#start_listener' do
6
+ let(:consumer) { instance_double(Kafka::Consumer) }
7
+ let(:handler) { class_double(Deimos::Utils::MessageBankHandler) }
8
+
9
+ before(:each) do
10
+ allow(handler).to receive(:start)
11
+ allow(consumer).to receive(:subscribe)
12
+ allow_any_instance_of(Phobos::Listener).to receive(:create_kafka_consumer).and_return(consumer)
13
+ allow_any_instance_of(Kafka::Client).to receive(:last_offset_for).and_return(100)
14
+ stub_const('Deimos::Utils::SeekListener::MAX_SEEK_RETRIES', 2)
15
+ end
16
+
17
+ it 'should seek offset' do
18
+ allow(consumer).to receive(:seek)
19
+ expect(consumer).to receive(:seek).once
20
+ seek_listener = described_class.new({ handler: handler, group_id: 999, topic: 'test_topic' })
21
+ seek_listener.start_listener
22
+ end
23
+
24
+ it 'should retry on errors when seeking offset' do
25
+ allow(consumer).to receive(:seek).and_raise(StandardError)
26
+ expect(consumer).to receive(:seek).twice
27
+ seek_listener = described_class.new({ handler: handler, group_id: 999, topic: 'test_topic' })
28
+ seek_listener.start_listener
29
+ end
30
+ end
31
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deimos-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.3
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Orner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-18 00:00:00.000000000 Z
11
+ date: 2021-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: avro_turf
@@ -28,30 +28,36 @@ dependencies:
28
28
  name: phobos
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.9'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '3.0'
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
- - - "~>"
41
+ - - ">="
39
42
  - !ruby/object:Gem::Version
40
43
  version: '1.9'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.0'
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: ruby-kafka
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
- - - "~>"
51
+ - - "<"
46
52
  - !ruby/object:Gem::Version
47
- version: '0.7'
53
+ version: '2'
48
54
  type: :runtime
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
51
57
  requirements:
52
- - - "~>"
58
+ - - "<"
53
59
  - !ruby/object:Gem::Version
54
- version: '0.7'
60
+ version: '2'
55
61
  - !ruby/object:Gem::Dependency
56
62
  name: sigurd
57
63
  requirement: !ruby/object:Gem::Requirement
@@ -280,30 +286,30 @@ dependencies:
280
286
  name: rubocop
281
287
  requirement: !ruby/object:Gem::Requirement
282
288
  requirements:
283
- - - "~>"
289
+ - - '='
284
290
  - !ruby/object:Gem::Version
285
- version: '0.72'
291
+ version: 0.88.0
286
292
  type: :development
287
293
  prerelease: false
288
294
  version_requirements: !ruby/object:Gem::Requirement
289
295
  requirements:
290
- - - "~>"
296
+ - - '='
291
297
  - !ruby/object:Gem::Version
292
- version: '0.72'
298
+ version: 0.88.0
293
299
  - !ruby/object:Gem::Dependency
294
300
  name: rubocop-rspec
295
301
  requirement: !ruby/object:Gem::Requirement
296
302
  requirements:
297
- - - "~>"
303
+ - - '='
298
304
  - !ruby/object:Gem::Version
299
- version: '1.27'
305
+ version: 1.42.0
300
306
  type: :development
301
307
  prerelease: false
302
308
  version_requirements: !ruby/object:Gem::Requirement
303
309
  requirements:
304
- - - "~>"
310
+ - - '='
305
311
  - !ruby/object:Gem::Version
306
- version: '1.27'
312
+ version: 1.42.0
307
313
  - !ruby/object:Gem::Dependency
308
314
  name: sqlite3
309
315
  requirement: !ruby/object:Gem::Requirement
@@ -465,6 +471,7 @@ files:
465
471
  - spec/utils/db_poller_spec.rb
466
472
  - spec/utils/db_producer_spec.rb
467
473
  - spec/utils/deadlock_retry_spec.rb
474
+ - spec/utils/inline_consumer_spec.rb
468
475
  - spec/utils/lag_reporter_spec.rb
469
476
  - spec/utils/platform_schema_validation_spec.rb
470
477
  - spec/utils/schema_controller_mixin_spec.rb
@@ -491,7 +498,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
491
498
  - !ruby/object:Gem::Version
492
499
  version: '0'
493
500
  requirements: []
494
- rubygems_version: 3.1.3
501
+ rubygems_version: 3.0.9
495
502
  signing_key:
496
503
  specification_version: 4
497
504
  summary: Kafka libraries for Ruby.
@@ -548,6 +555,7 @@ test_files:
548
555
  - spec/utils/db_poller_spec.rb
549
556
  - spec/utils/db_producer_spec.rb
550
557
  - spec/utils/deadlock_retry_spec.rb
558
+ - spec/utils/inline_consumer_spec.rb
551
559
  - spec/utils/lag_reporter_spec.rb
552
560
  - spec/utils/platform_schema_validation_spec.rb
553
561
  - spec/utils/schema_controller_mixin_spec.rb