deimos-ruby 1.8.0.pre.beta2 → 1.8.1.pre.beta5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -4
  3. data/CHANGELOG.md +40 -0
  4. data/Gemfile.lock +101 -73
  5. data/README.md +78 -2
  6. data/deimos-ruby.gemspec +2 -2
  7. data/lib/deimos.rb +4 -3
  8. data/lib/deimos/active_record_consume/batch_consumption.rb +7 -2
  9. data/lib/deimos/active_record_consume/message_consumption.rb +8 -1
  10. data/lib/deimos/instrumentation.rb +10 -5
  11. data/lib/deimos/kafka_topic_info.rb +21 -2
  12. data/lib/deimos/schema_backends/avro_base.rb +33 -1
  13. data/lib/deimos/schema_backends/avro_schema_coercer.rb +30 -9
  14. data/lib/deimos/schema_backends/base.rb +21 -2
  15. data/lib/deimos/utils/db_producer.rb +57 -19
  16. data/lib/deimos/utils/schema_controller_mixin.rb +111 -0
  17. data/lib/deimos/version.rb +1 -1
  18. data/lib/generators/deimos/active_record/templates/migration.rb.tt +28 -0
  19. data/lib/generators/deimos/active_record/templates/model.rb.tt +5 -0
  20. data/lib/generators/deimos/active_record_generator.rb +79 -0
  21. data/lib/generators/deimos/db_backend/templates/migration +1 -0
  22. data/lib/generators/deimos/db_backend/templates/rails3_migration +1 -0
  23. data/spec/generators/active_record_generator_spec.rb +56 -0
  24. data/spec/kafka_listener_spec.rb +55 -0
  25. data/spec/kafka_topic_info_spec.rb +39 -16
  26. data/spec/producer_spec.rb +36 -0
  27. data/spec/schemas/com/my-namespace/Generated.avsc +71 -0
  28. data/spec/schemas/com/my-namespace/MyNestedSchema.avsc +62 -0
  29. data/spec/schemas/com/my-namespace/request/Index.avsc +11 -0
  30. data/spec/schemas/com/my-namespace/request/UpdateRequest.avsc +11 -0
  31. data/spec/schemas/com/my-namespace/response/Index.avsc +11 -0
  32. data/spec/schemas/com/my-namespace/response/UpdateResponse.avsc +11 -0
  33. data/spec/spec_helper.rb +7 -0
  34. data/spec/utils/db_producer_spec.rb +84 -10
  35. data/spec/utils/schema_controller_mixin_spec.rb +68 -0
  36. metadata +40 -24
@@ -0,0 +1,11 @@
1
+ {
2
+ "namespace": "com.my-namespace.request",
3
+ "name": "Index",
4
+ "type": "record",
5
+ "fields": [
6
+ {
7
+ "name": "request_id",
8
+ "type": "string"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "namespace": "com.my-namespace.request",
3
+ "name": "UpdateRequest",
4
+ "type": "record",
5
+ "fields": [
6
+ {
7
+ "name": "update_request_id",
8
+ "type": "string"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "namespace": "com.my-namespace.response",
3
+ "name": "Index",
4
+ "type": "record",
5
+ "fields": [
6
+ {
7
+ "name": "response_id",
8
+ "type": "string"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "namespace": "com.my-namespace.response",
3
+ "name": "UpdateResponse",
4
+ "type": "record",
5
+ "fields": [
6
+ {
7
+ "name": "update_response_id",
8
+ "type": "string"
9
+ }
10
+ ]
11
+ }
@@ -2,6 +2,7 @@
2
2
 
3
3
  $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
4
4
  require 'active_record'
5
+ require 'action_controller/railtie'
5
6
  require 'database_cleaner'
6
7
  require 'deimos'
7
8
  require 'deimos/metrics/mock'
@@ -11,6 +12,11 @@ require 'active_support/testing/time_helpers'
11
12
  require 'activerecord-import'
12
13
  require 'handlers/my_batch_consumer'
13
14
  require 'handlers/my_consumer'
15
+ require 'rspec/rails'
16
+
17
+ class DeimosApp < Rails::Application
18
+ end
19
+ DeimosApp.initialize!
14
20
 
15
21
  # Helpers for Executor/DbProducer
16
22
  module TestRunners
@@ -32,6 +38,7 @@ module TestRunners
32
38
  # Test runner
33
39
  class TestRunner
34
40
  attr_accessor :id, :started, :stopped, :should_error
41
+
35
42
  # :nodoc:
36
43
  def initialize(id=nil)
37
44
  @id = id
@@ -16,11 +16,13 @@ each_db_config(Deimos::Utils::DbProducer) do
16
16
 
17
17
  before(:each) do
18
18
  stub_const('Deimos::Utils::DbProducer::BATCH_SIZE', 2)
19
+ stub_const('Deimos::Utils::DbProducer::DELETE_BATCH_SIZE', 1)
19
20
  end
20
21
 
21
22
  specify '#process_next_messages' do
22
23
  expect(producer).to receive(:retrieve_topics).and_return(%w(topic1 topic2))
23
24
  expect(producer).to receive(:process_topic).twice
25
+ expect(Deimos::KafkaTopicInfo).to receive(:ping_empty_topics).with(%w(topic1 topic2))
24
26
  expect(producer).to receive(:sleep).with(0.5)
25
27
  producer.process_next_messages
26
28
  end
@@ -40,6 +42,9 @@ each_db_config(Deimos::Utils::DbProducer) do
40
42
  Deimos::KafkaMessage.create!(topic: 'topic1',
41
43
  message: 'blah',
42
44
  key: "key#{i}")
45
+ Deimos::KafkaMessage.create!(topic: 'topic2',
46
+ message: 'blah',
47
+ key: "key#{i}")
43
48
  end
44
49
  stub_const('Deimos::Utils::DbProducer::BATCH_SIZE', 5)
45
50
  producer.current_topic = 'topic1'
@@ -280,6 +285,12 @@ each_db_config(Deimos::Utils::DbProducer) do
280
285
  message: "mess#{i}",
281
286
  partition_key: "key#{i}"
282
287
  )
288
+ Deimos::KafkaMessage.create!(
289
+ id: i,
290
+ topic: 'my-topic2',
291
+ message: "mess#{i}",
292
+ partition_key: "key#{i}"
293
+ )
283
294
  end
284
295
 
285
296
  expect(Deimos::KafkaTopicInfo).to receive(:lock).
@@ -288,9 +299,60 @@ each_db_config(Deimos::Utils::DbProducer) do
288
299
  expect(producer).to receive(:retrieve_messages).and_return(messages)
289
300
  expect(Deimos::KafkaTopicInfo).to receive(:register_error)
290
301
 
302
+ expect(Deimos::KafkaMessage.count).to eq(8)
303
+ producer.process_topic('my-topic')
291
304
  expect(Deimos::KafkaMessage.count).to eq(4)
305
+ end
306
+
307
+ it 'should retry deletes and not re-publish' do
308
+ messages = (1..4).map do |i|
309
+ Deimos::KafkaMessage.create!(
310
+ id: i,
311
+ topic: 'my-topic',
312
+ message: "mess#{i}",
313
+ partition_key: "key#{i}"
314
+ )
315
+ end
316
+ (5..8).each do |i|
317
+ Deimos::KafkaMessage.create!(
318
+ id: i,
319
+ topic: 'my-topic2',
320
+ message: "mess#{i}",
321
+ partition_key: "key#{i}"
322
+ )
323
+ end
324
+
325
+ raise_error = true
326
+ expect(Deimos::KafkaMessage).to receive(:where).exactly(5).times.and_wrap_original do |m, *args|
327
+ if raise_error
328
+ raise_error = false
329
+ raise 'Lock wait timeout'
330
+ end
331
+ m.call(*args)
332
+ end
333
+
334
+ expect(Deimos::KafkaTopicInfo).to receive(:lock).
335
+ with('my-topic', 'abc').and_return(true)
336
+ expect(producer).to receive(:retrieve_messages).ordered.and_return(messages)
337
+ expect(producer).to receive(:retrieve_messages).ordered.and_return([])
338
+ expect(phobos_producer).to receive(:publish_list).once.with(messages.map(&:phobos_message))
339
+
340
+ expect(Deimos::KafkaMessage.count).to eq(8)
292
341
  producer.process_topic('my-topic')
293
- expect(Deimos::KafkaMessage.count).to eq(0)
342
+ expect(Deimos::KafkaMessage.count).to eq(4)
343
+ end
344
+
345
+ it 'should re-raise misc errors on delete' do
346
+ messages = (1..3).map do |i|
347
+ Deimos::KafkaMessage.create!(
348
+ id: i,
349
+ topic: 'my-topic',
350
+ message: "mess#{i}",
351
+ partition_key: "key#{i}"
352
+ )
353
+ end
354
+ expect(Deimos::KafkaMessage).to receive(:where).once.and_raise('OH NOES')
355
+ expect { producer.delete_messages(messages) }.to raise_exception('OH NOES')
294
356
  end
295
357
 
296
358
  end
@@ -309,21 +371,34 @@ each_db_config(Deimos::Utils::DbProducer) do
309
371
  Deimos::KafkaMessage.create!(topic: "topic#{i}", message: nil,
310
372
  created_at: (1 + i).minute.ago)
311
373
  end
374
+ Deimos::KafkaTopicInfo.create!(topic: 'topic1',
375
+ last_processed_at: 6.minutes.ago)
376
+ Deimos::KafkaTopicInfo.create!(topic: 'topic2',
377
+ last_processed_at: 3.minutes.ago)
378
+ Deimos::KafkaTopicInfo.create!(topic: 'topic3',
379
+ last_processed_at: 5.minutes.ago)
312
380
  allow(Deimos.config.metrics).to receive(:gauge)
313
381
  producer.send_pending_metrics
314
- expect(Deimos.config.metrics).to have_received(:gauge).twice
382
+ expect(Deimos.config.metrics).to have_received(:gauge).exactly(6).times
383
+ # topic1 has the earliest message 4 minutes ago and last processed 6
384
+ # minutes ago, so the most amount of time we've seen nothing is 4 minutes
315
385
  expect(Deimos.config.metrics).to have_received(:gauge).
316
386
  with('pending_db_messages_max_wait', 4.minutes.to_i, tags: ['topic:topic1'])
387
+ # topic2 has earliest message 5 minutes ago and last processed 3 minutes
388
+ # ago, so we should give it 3 minutes
389
+ expect(Deimos.config.metrics).to have_received(:gauge).
390
+ with('pending_db_messages_max_wait', 3.minutes.to_i, tags: ['topic:topic2'])
391
+ # topic3 has no messages, so should get 0
317
392
  expect(Deimos.config.metrics).to have_received(:gauge).
318
- with('pending_db_messages_max_wait', 5.minutes.to_i, tags: ['topic:topic2'])
393
+ with('pending_db_messages_max_wait', 0, tags: ['topic:topic3'])
394
+ expect(Deimos.config.metrics).to have_received(:gauge).
395
+ with('pending_db_messages_count', 3, tags: ['topic:topic1'])
396
+ expect(Deimos.config.metrics).to have_received(:gauge).
397
+ with('pending_db_messages_count', 3, tags: ['topic:topic2'])
398
+ expect(Deimos.config.metrics).to have_received(:gauge).
399
+ with('pending_db_messages_count', 0, tags: ['topic:topic3'])
319
400
  end
320
401
  end
321
-
322
- it 'should send 0 if no messages' do
323
- expect(Deimos.config.metrics).to receive(:gauge).
324
- with('pending_db_messages_max_wait', 0)
325
- producer.send_pending_metrics
326
- end
327
402
  end
328
403
 
329
404
  example 'Full integration test' do
@@ -403,5 +478,4 @@ each_db_config(Deimos::Utils::DbProducer) do
403
478
  }
404
479
  ])
405
480
  end
406
-
407
481
  end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'deimos/utils/schema_controller_mixin'
4
+ require 'deimos/schema_backends/avro_local'
5
+
6
+ RSpec.describe Deimos::Utils::SchemaControllerMixin, type: :controller do
7
+
8
+ before(:each) do
9
+ Deimos.configure do
10
+ schema.backend(:avro_local)
11
+ end
12
+ end
13
+
14
+ controller(ActionController::Base) do
15
+ include Deimos::Utils::SchemaControllerMixin # rubocop:disable RSpec/DescribedClass
16
+
17
+ request_namespace 'com.my-namespace.request'
18
+ response_namespace 'com.my-namespace.response'
19
+ schemas :index, :show
20
+ schemas :update, request: 'UpdateRequest', response: 'UpdateResponse'
21
+
22
+ # :nodoc:
23
+ def index
24
+ render_schema({ 'response_id' => payload[:request_id] + ' mom' })
25
+ end
26
+
27
+ # :nodoc:
28
+ def show
29
+ render_schema({ 'response_id' => payload[:request_id] + ' dad' })
30
+ end
31
+
32
+ # :nodoc:
33
+ def update
34
+ render_schema({ 'update_response_id' => payload[:update_request_id] + ' sis' })
35
+ end
36
+ end
37
+
38
+ it 'should render the correct response for index' do
39
+ request_backend = Deimos.schema_backend(schema: 'Index',
40
+ namespace: 'com.my-namespace.request')
41
+ response_backend = Deimos.schema_backend(schema: 'Index',
42
+ namespace: 'com.my-namespace.response')
43
+ request.content_type = 'avro/binary'
44
+ get :index, body: request_backend.encode({ 'request_id' => 'hi' })
45
+ expect(response_backend.decode(response.body)).to eq({ 'response_id' => 'hi mom' })
46
+ end
47
+
48
+ it 'should render the correct response for show' do
49
+ request_backend = Deimos.schema_backend(schema: 'Index',
50
+ namespace: 'com.my-namespace.request')
51
+ response_backend = Deimos.schema_backend(schema: 'Index',
52
+ namespace: 'com.my-namespace.response')
53
+ request.content_type = 'avro/binary'
54
+ get :show, params: { id: 1 }, body: request_backend.encode({ 'request_id' => 'hi' })
55
+ expect(response_backend.decode(response.body)).to eq({ 'response_id' => 'hi dad' })
56
+ end
57
+
58
+ it 'should render the correct response for update' do
59
+ request_backend = Deimos.schema_backend(schema: 'UpdateRequest',
60
+ namespace: 'com.my-namespace.request')
61
+ response_backend = Deimos.schema_backend(schema: 'UpdateResponse',
62
+ namespace: 'com.my-namespace.response')
63
+ request.content_type = 'avro/binary'
64
+ post :update, params: { id: 1 }, body: request_backend.encode({ 'update_request_id' => 'hi' })
65
+ expect(response_backend.decode(response.body)).to eq({ 'update_response_id' => 'hi sis' })
66
+ end
67
+
68
+ 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.0.pre.beta2
4
+ version: 1.8.1.pre.beta5
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-07-08 00:00:00.000000000 Z
11
+ date: 2020-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: avro_turf
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.0.1
69
- - !ruby/object:Gem::Dependency
70
- name: activerecord
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '5.2'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '5.2'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: activerecord-import
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -226,20 +212,14 @@ dependencies:
226
212
  requirements:
227
213
  - - "~>"
228
214
  - !ruby/object:Gem::Version
229
- version: '5.2'
230
- - - ">="
231
- - !ruby/object:Gem::Version
232
- version: 5.2.4.2
215
+ version: '6'
233
216
  type: :development
234
217
  prerelease: false
235
218
  version_requirements: !ruby/object:Gem::Requirement
236
219
  requirements:
237
220
  - - "~>"
238
221
  - !ruby/object:Gem::Version
239
- version: '5.2'
240
- - - ">="
241
- - !ruby/object:Gem::Version
242
- version: 5.2.4.2
222
+ version: '6'
243
223
  - !ruby/object:Gem::Dependency
244
224
  name: rake
245
225
  requirement: !ruby/object:Gem::Requirement
@@ -282,6 +262,20 @@ dependencies:
282
262
  - - "~>"
283
263
  - !ruby/object:Gem::Version
284
264
  version: '0.3'
265
+ - !ruby/object:Gem::Dependency
266
+ name: rspec-rails
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - "~>"
270
+ - !ruby/object:Gem::Version
271
+ version: '4'
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - "~>"
277
+ - !ruby/object:Gem::Version
278
+ version: '4'
285
279
  - !ruby/object:Gem::Dependency
286
280
  name: rubocop
287
281
  requirement: !ruby/object:Gem::Requirement
@@ -405,7 +399,11 @@ files:
405
399
  - lib/deimos/utils/deadlock_retry.rb
406
400
  - lib/deimos/utils/inline_consumer.rb
407
401
  - lib/deimos/utils/lag_reporter.rb
402
+ - lib/deimos/utils/schema_controller_mixin.rb
408
403
  - lib/deimos/version.rb
404
+ - lib/generators/deimos/active_record/templates/migration.rb.tt
405
+ - lib/generators/deimos/active_record/templates/model.rb.tt
406
+ - lib/generators/deimos/active_record_generator.rb
409
407
  - lib/generators/deimos/db_backend/templates/migration
410
408
  - lib/generators/deimos/db_backend/templates/rails3_migration
411
409
  - lib/generators/deimos/db_backend_generator.rb
@@ -427,8 +425,10 @@ files:
427
425
  - spec/config/configuration_spec.rb
428
426
  - spec/consumer_spec.rb
429
427
  - spec/deimos_spec.rb
428
+ - spec/generators/active_record_generator_spec.rb
430
429
  - spec/handlers/my_batch_consumer.rb
431
430
  - spec/handlers/my_consumer.rb
431
+ - spec/kafka_listener_spec.rb
432
432
  - spec/kafka_source_spec.rb
433
433
  - spec/kafka_topic_info_spec.rb
434
434
  - spec/message_spec.rb
@@ -441,6 +441,8 @@ files:
441
441
  - spec/schema_backends/avro_schema_registry_spec.rb
442
442
  - spec/schema_backends/avro_validation_spec.rb
443
443
  - spec/schema_backends/base_spec.rb
444
+ - spec/schemas/com/my-namespace/Generated.avsc
445
+ - spec/schemas/com/my-namespace/MyNestedSchema.avsc
444
446
  - spec/schemas/com/my-namespace/MySchema-key.avsc
445
447
  - spec/schemas/com/my-namespace/MySchema.avsc
446
448
  - spec/schemas/com/my-namespace/MySchemaCompound-key.avsc
@@ -451,12 +453,17 @@ files:
451
453
  - spec/schemas/com/my-namespace/Wibble.avsc
452
454
  - spec/schemas/com/my-namespace/Widget.avsc
453
455
  - spec/schemas/com/my-namespace/WidgetTheSecond.avsc
456
+ - spec/schemas/com/my-namespace/request/Index.avsc
457
+ - spec/schemas/com/my-namespace/request/UpdateRequest.avsc
458
+ - spec/schemas/com/my-namespace/response/Index.avsc
459
+ - spec/schemas/com/my-namespace/response/UpdateResponse.avsc
454
460
  - spec/spec_helper.rb
455
461
  - spec/utils/db_poller_spec.rb
456
462
  - spec/utils/db_producer_spec.rb
457
463
  - spec/utils/deadlock_retry_spec.rb
458
464
  - spec/utils/lag_reporter_spec.rb
459
465
  - spec/utils/platform_schema_validation_spec.rb
466
+ - spec/utils/schema_controller_mixin_spec.rb
460
467
  - support/deimos-solo.png
461
468
  - support/deimos-with-name-next.png
462
469
  - support/deimos-with-name.png
@@ -499,8 +506,10 @@ test_files:
499
506
  - spec/config/configuration_spec.rb
500
507
  - spec/consumer_spec.rb
501
508
  - spec/deimos_spec.rb
509
+ - spec/generators/active_record_generator_spec.rb
502
510
  - spec/handlers/my_batch_consumer.rb
503
511
  - spec/handlers/my_consumer.rb
512
+ - spec/kafka_listener_spec.rb
504
513
  - spec/kafka_source_spec.rb
505
514
  - spec/kafka_topic_info_spec.rb
506
515
  - spec/message_spec.rb
@@ -513,6 +522,8 @@ test_files:
513
522
  - spec/schema_backends/avro_schema_registry_spec.rb
514
523
  - spec/schema_backends/avro_validation_spec.rb
515
524
  - spec/schema_backends/base_spec.rb
525
+ - spec/schemas/com/my-namespace/Generated.avsc
526
+ - spec/schemas/com/my-namespace/MyNestedSchema.avsc
516
527
  - spec/schemas/com/my-namespace/MySchema-key.avsc
517
528
  - spec/schemas/com/my-namespace/MySchema.avsc
518
529
  - spec/schemas/com/my-namespace/MySchemaCompound-key.avsc
@@ -523,9 +534,14 @@ test_files:
523
534
  - spec/schemas/com/my-namespace/Wibble.avsc
524
535
  - spec/schemas/com/my-namespace/Widget.avsc
525
536
  - spec/schemas/com/my-namespace/WidgetTheSecond.avsc
537
+ - spec/schemas/com/my-namespace/request/Index.avsc
538
+ - spec/schemas/com/my-namespace/request/UpdateRequest.avsc
539
+ - spec/schemas/com/my-namespace/response/Index.avsc
540
+ - spec/schemas/com/my-namespace/response/UpdateResponse.avsc
526
541
  - spec/spec_helper.rb
527
542
  - spec/utils/db_poller_spec.rb
528
543
  - spec/utils/db_producer_spec.rb
529
544
  - spec/utils/deadlock_retry_spec.rb
530
545
  - spec/utils/lag_reporter_spec.rb
531
546
  - spec/utils/platform_schema_validation_spec.rb
547
+ - spec/utils/schema_controller_mixin_spec.rb