deimos-ruby 1.24.2 → 2.0.0.pre.alpha1

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +0 -17
  3. data/.tool-versions +1 -0
  4. data/CHANGELOG.md +5 -0
  5. data/README.md +287 -498
  6. data/deimos-ruby.gemspec +4 -4
  7. data/docs/CONFIGURATION.md +133 -226
  8. data/docs/UPGRADING.md +237 -0
  9. data/lib/deimos/active_record_consume/batch_consumption.rb +29 -28
  10. data/lib/deimos/active_record_consume/mass_updater.rb +59 -4
  11. data/lib/deimos/active_record_consume/message_consumption.rb +15 -21
  12. data/lib/deimos/active_record_consumer.rb +36 -21
  13. data/lib/deimos/active_record_producer.rb +28 -9
  14. data/lib/deimos/backends/base.rb +4 -35
  15. data/lib/deimos/backends/kafka.rb +6 -22
  16. data/lib/deimos/backends/kafka_async.rb +6 -22
  17. data/lib/deimos/backends/{db.rb → outbox.rb} +13 -9
  18. data/lib/deimos/config/configuration.rb +116 -379
  19. data/lib/deimos/consume/batch_consumption.rb +24 -124
  20. data/lib/deimos/consume/message_consumption.rb +36 -63
  21. data/lib/deimos/consumer.rb +16 -75
  22. data/lib/deimos/ext/consumer_route.rb +35 -0
  23. data/lib/deimos/ext/producer_middleware.rb +94 -0
  24. data/lib/deimos/ext/producer_route.rb +22 -0
  25. data/lib/deimos/ext/redraw.rb +29 -0
  26. data/lib/deimos/ext/routing_defaults.rb +72 -0
  27. data/lib/deimos/ext/schema_route.rb +70 -0
  28. data/lib/deimos/kafka_message.rb +2 -2
  29. data/lib/deimos/kafka_source.rb +2 -7
  30. data/lib/deimos/kafka_topic_info.rb +1 -1
  31. data/lib/deimos/logging.rb +71 -0
  32. data/lib/deimos/message.rb +2 -11
  33. data/lib/deimos/metrics/datadog.rb +40 -1
  34. data/lib/deimos/metrics/provider.rb +4 -4
  35. data/lib/deimos/producer.rb +39 -116
  36. data/lib/deimos/railtie.rb +6 -0
  37. data/lib/deimos/schema_backends/avro_base.rb +21 -21
  38. data/lib/deimos/schema_backends/avro_schema_registry.rb +1 -2
  39. data/lib/deimos/schema_backends/avro_validation.rb +2 -2
  40. data/lib/deimos/schema_backends/base.rb +19 -12
  41. data/lib/deimos/schema_backends/mock.rb +6 -1
  42. data/lib/deimos/schema_backends/plain.rb +47 -0
  43. data/lib/deimos/schema_class/base.rb +2 -2
  44. data/lib/deimos/schema_class/enum.rb +1 -1
  45. data/lib/deimos/schema_class/record.rb +2 -2
  46. data/lib/deimos/test_helpers.rb +95 -320
  47. data/lib/deimos/tracing/provider.rb +6 -6
  48. data/lib/deimos/transcoder.rb +88 -0
  49. data/lib/deimos/utils/db_poller/base.rb +16 -14
  50. data/lib/deimos/utils/db_poller/state_based.rb +3 -3
  51. data/lib/deimos/utils/db_poller/time_based.rb +4 -4
  52. data/lib/deimos/utils/db_poller.rb +1 -1
  53. data/lib/deimos/utils/deadlock_retry.rb +1 -1
  54. data/lib/deimos/utils/{db_producer.rb → outbox_producer.rb} +16 -47
  55. data/lib/deimos/utils/schema_class.rb +0 -7
  56. data/lib/deimos/version.rb +1 -1
  57. data/lib/deimos.rb +79 -26
  58. data/lib/generators/deimos/{db_backend_generator.rb → outbox_backend_generator.rb} +4 -4
  59. data/lib/generators/deimos/schema_class_generator.rb +0 -1
  60. data/lib/generators/deimos/v2/templates/karafka.rb.tt +149 -0
  61. data/lib/generators/deimos/v2_generator.rb +193 -0
  62. data/lib/tasks/deimos.rake +5 -7
  63. data/spec/active_record_batch_consumer_association_spec.rb +22 -13
  64. data/spec/active_record_batch_consumer_spec.rb +84 -65
  65. data/spec/active_record_consume/batch_consumption_spec.rb +10 -10
  66. data/spec/active_record_consume/batch_slicer_spec.rb +12 -12
  67. data/spec/active_record_consume/mass_updater_spec.rb +137 -0
  68. data/spec/active_record_consumer_spec.rb +29 -13
  69. data/spec/active_record_producer_spec.rb +36 -26
  70. data/spec/backends/base_spec.rb +0 -23
  71. data/spec/backends/kafka_async_spec.rb +1 -3
  72. data/spec/backends/kafka_spec.rb +1 -3
  73. data/spec/backends/{db_spec.rb → outbox_spec.rb} +14 -20
  74. data/spec/batch_consumer_spec.rb +66 -116
  75. data/spec/consumer_spec.rb +53 -147
  76. data/spec/deimos_spec.rb +10 -126
  77. data/spec/kafka_source_spec.rb +19 -52
  78. data/spec/karafka/karafka.rb +69 -0
  79. data/spec/karafka_config/karafka_spec.rb +97 -0
  80. data/spec/logging_spec.rb +25 -0
  81. data/spec/message_spec.rb +9 -9
  82. data/spec/producer_spec.rb +112 -254
  83. data/spec/rake_spec.rb +1 -3
  84. data/spec/schema_backends/avro_validation_spec.rb +1 -1
  85. data/spec/schemas/com/my-namespace/MySchemaWithTitle.avsc +22 -0
  86. data/spec/snapshots/consumers-no-nest.snap +49 -0
  87. data/spec/snapshots/consumers.snap +49 -0
  88. data/spec/snapshots/consumers_and_producers-no-nest.snap +49 -0
  89. data/spec/snapshots/consumers_and_producers.snap +49 -0
  90. data/spec/snapshots/consumers_circular-no-nest.snap +49 -0
  91. data/spec/snapshots/consumers_circular.snap +49 -0
  92. data/spec/snapshots/consumers_complex_types-no-nest.snap +49 -0
  93. data/spec/snapshots/consumers_complex_types.snap +49 -0
  94. data/spec/snapshots/consumers_nested-no-nest.snap +49 -0
  95. data/spec/snapshots/consumers_nested.snap +49 -0
  96. data/spec/snapshots/namespace_folders.snap +49 -0
  97. data/spec/snapshots/namespace_map.snap +49 -0
  98. data/spec/snapshots/producers_with_key-no-nest.snap +49 -0
  99. data/spec/snapshots/producers_with_key.snap +49 -0
  100. data/spec/spec_helper.rb +61 -29
  101. data/spec/utils/db_poller_spec.rb +49 -39
  102. data/spec/utils/{db_producer_spec.rb → outbox_producer_spec.rb} +17 -184
  103. metadata +58 -67
  104. data/lib/deimos/batch_consumer.rb +0 -7
  105. data/lib/deimos/config/phobos_config.rb +0 -163
  106. data/lib/deimos/instrumentation.rb +0 -95
  107. data/lib/deimos/monkey_patches/phobos_cli.rb +0 -35
  108. data/lib/deimos/utils/inline_consumer.rb +0 -158
  109. data/lib/deimos/utils/lag_reporter.rb +0 -186
  110. data/lib/deimos/utils/schema_controller_mixin.rb +0 -129
  111. data/spec/config/configuration_spec.rb +0 -321
  112. data/spec/kafka_listener_spec.rb +0 -55
  113. data/spec/phobos.bad_db.yml +0 -73
  114. data/spec/phobos.yml +0 -77
  115. data/spec/utils/inline_consumer_spec.rb +0 -31
  116. data/spec/utils/lag_reporter_spec.rb +0 -76
  117. data/spec/utils/platform_schema_validation_spec.rb +0 -0
  118. data/spec/utils/schema_controller_mixin_spec.rb +0 -84
  119. /data/lib/generators/deimos/{db_backend → outbox_backend}/templates/migration +0 -0
  120. /data/lib/generators/deimos/{db_backend → outbox_backend}/templates/rails3_migration +0 -0
data/spec/spec_helper.rb CHANGED
@@ -14,6 +14,7 @@ require 'handlers/my_batch_consumer'
14
14
  require 'handlers/my_consumer'
15
15
  require 'rspec/rails'
16
16
  require 'rspec/snapshot'
17
+ require 'karafka/testing/rspec/helpers'
17
18
  require "trilogy_adapter/connection"
18
19
  ActiveRecord::Base.public_send :extend, TrilogyAdapter::Connection
19
20
  Dir['./spec/schemas/**/*.rb'].sort.each { |f| require f }
@@ -23,9 +24,33 @@ SCHEMA_CLASS_SETTINGS = { off: false, on: true }.freeze
23
24
 
24
25
  class DeimosApp < Rails::Application
25
26
  end
27
+ DeimosApp.initializer("setup_root_dir", before: "karafka.require_karafka_boot_file") do
28
+ ENV['KARAFKA_ROOT_DIR'] = "#{Rails.root}/spec/karafka"
29
+ end
26
30
  DeimosApp.initialize!
27
31
 
28
- # Helpers for Executor/DbProducer
32
+ module Helpers
33
+
34
+ def set_karafka_config(method, val)
35
+ Deimos.karafka_configs.each { |c| c.send(method.to_sym, val) }
36
+ end
37
+
38
+ def register_consumer(klass, schema, namespace='com.my-namespace', key_config:{none: true}, configs: {})
39
+ Karafka::App.routes.redraw do
40
+ topic 'my-topic' do
41
+ consumer klass
42
+ schema schema
43
+ namespace namespace
44
+ key_config key_config
45
+ configs.each do |k, v|
46
+ public_send(k, v)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ # Helpers for Executor/OutboxProducer
29
54
  module TestRunners
30
55
  # Execute a block until it stops failing. This is helpful for testing threads
31
56
  # where we need to wait for them to continue but don't want to rely on
@@ -73,11 +98,7 @@ module DbConfigs
73
98
  # @param topic [String]
74
99
  # @param key [String]
75
100
  def build_message(payload, topic, key)
76
- message = Deimos::Message.new(payload, Deimos::Producer,
77
- topic: topic, key: key)
78
- message.encoded_payload = message.payload
79
- message.encoded_key = message.key
80
- message
101
+ { payload: payload, topic: topic, key: key}
81
102
  end
82
103
 
83
104
  DB_OPTIONS = [
@@ -85,12 +106,12 @@ module DbConfigs
85
106
  adapter: 'postgresql',
86
107
  port: 5432,
87
108
  username: 'postgres',
88
- password: 'root',
109
+ password: 'password',
89
110
  database: 'postgres',
90
111
  host: ENV['PG_HOST'] || 'localhost'
91
112
  },
92
113
  {
93
- adapter: 'mysql2',
114
+ adapter: 'trilogy',
94
115
  port: 3306,
95
116
  username: 'root',
96
117
  database: 'test',
@@ -123,14 +144,14 @@ module DbConfigs
123
144
  end
124
145
 
125
146
  # :nodoc:
126
- def run_db_backend_migration
127
- migration_class_name = 'DbBackendMigration'
147
+ def run_outbox_backend_migration
148
+ migration_class_name = 'OutboxBackendMigration'
128
149
  migration_version = '[5.2]'
129
150
  migration = ERB.new(
130
- File.read('lib/generators/deimos/db_backend/templates/migration')
151
+ File.read('lib/generators/deimos/outbox_backend/templates/migration')
131
152
  ).result(binding)
132
153
  eval(migration) # rubocop:disable Security/Eval
133
- ActiveRecord::Migration.new.run(DbBackendMigration, direction: :up)
154
+ ActiveRecord::Migration.new.run(OutboxBackendMigration, direction: :up)
134
155
  end
135
156
 
136
157
  # :nodoc:
@@ -147,7 +168,7 @@ module DbConfigs
147
168
  # Set up the given database.
148
169
  def setup_db(options)
149
170
  ActiveRecord::Base.establish_connection(options)
150
- run_db_backend_migration
171
+ run_outbox_backend_migration
151
172
  run_db_poller_migration
152
173
 
153
174
  ActiveRecord::Base.descendants.each do |klass|
@@ -163,7 +184,10 @@ end
163
184
  RSpec.configure do |config|
164
185
  config.extend(DbConfigs)
165
186
  include DbConfigs
187
+ config.include Karafka::Testing::RSpec::Helpers
188
+
166
189
  config.include TestRunners
190
+ config.include Helpers
167
191
  config.full_backtrace = true
168
192
 
169
193
  config.snapshot_dir = "spec/snapshots"
@@ -199,13 +223,11 @@ RSpec.configure do |config|
199
223
  config.before(:each) do
200
224
  Deimos.config.reset!
201
225
  Deimos.configure do |deimos_config|
202
- deimos_config.producers.backend = :test
226
+ deimos_config.producers.backend = :kafka
203
227
  deimos_config.schema.nest_child_schemas = true
204
- deimos_config.phobos_config_file = File.join(File.dirname(__FILE__), 'phobos.yml')
205
228
  deimos_config.schema.path = File.join(File.expand_path(__dir__), 'schemas')
206
229
  deimos_config.consumers.reraise_errors = true
207
230
  deimos_config.schema.registry_url = ENV['SCHEMA_REGISTRY'] || 'http://localhost:8081'
208
- deimos_config.kafka.seed_brokers = ENV['KAFKA_SEED_BROKER'] || 'localhost:9092'
209
231
  deimos_config.logger = Logger.new('/dev/null')
210
232
  deimos_config.logger.level = Logger::INFO
211
233
  deimos_config.schema.backend = :avro_validation
@@ -213,6 +235,10 @@ RSpec.configure do |config|
213
235
  end
214
236
  end
215
237
 
238
+ config.after(:each) do
239
+ Deimos::EVENT_TYPES.each { |type| Karafka.monitor.notifications_bus.clear(type) }
240
+ end
241
+
216
242
  config.around(:each) do |example|
217
243
  use_cleaner = !example.metadata[:integration]
218
244
 
@@ -262,26 +288,32 @@ end
262
288
 
263
289
  RSpec.shared_context('with publish_backend') do
264
290
  before(:each) do
265
- producer_class = Class.new(Deimos::Producer) do
266
- schema 'MySchema'
267
- namespace 'com.my-namespace'
268
- topic 'my-topic'
269
- key_config field: 'test_id'
270
- end
291
+ producer_class = Class.new(Deimos::Producer)
271
292
  stub_const('MyProducer', producer_class)
272
293
 
273
- producer_class = Class.new(Deimos::Producer) do
274
- schema 'MySchema'
275
- namespace 'com.my-namespace'
276
- topic 'my-topic'
277
- key_config none: true
278
- end
294
+ producer_class_no_key = Class.new(Deimos::Producer)
279
295
  stub_const('MyNoKeyProducer', producer_class)
296
+
297
+ Karafka::App.routes.redraw do
298
+ topic 'my-topic-no-key' do
299
+ schema 'MySchema'
300
+ namespace 'com.my-namespace'
301
+ key_config none: true
302
+ producer_class producer_class_no_key
303
+ end
304
+ topic 'my-topic' do
305
+ schema 'MySchema'
306
+ namespace 'com.my-namespace'
307
+ key_config field: 'test_id'
308
+ producer_class producer_class
309
+ end
310
+ end
311
+
280
312
  end
281
313
 
282
314
  let(:messages) do
283
315
  (1..3).map do |i|
284
- build_message({ foo: i }, 'my-topic', "foo#{i}")
316
+ build_message({ test_id: "foo#{i}", some_int: i }, 'my-topic', "foo#{i}")
285
317
  end
286
318
  end
287
319
  end
@@ -20,21 +20,27 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
20
20
  describe '#start!' do
21
21
 
22
22
  before(:each) do
23
- producer_class = Class.new(Deimos::Producer) do
24
- schema 'MySchema'
25
- namespace 'com.my-namespace'
26
- topic 'my-topic'
27
- key_config field: 'test_id'
28
- end
23
+ producer_class = Class.new(Deimos::Producer)
29
24
  stub_const('MyProducer', producer_class)
30
25
 
31
- producer_class = Class.new(Deimos::Producer) do
32
- schema 'MySchemaWithId'
33
- namespace 'com.my-namespace'
34
- topic 'my-topic'
35
- key_config plain: true
36
- end
26
+ producer_class = Class.new(Deimos::Producer)
37
27
  stub_const('MyProducerWithID', producer_class)
28
+
29
+ Karafka::App.routes.redraw do
30
+ topic 'my-topic' do
31
+ schema 'MySchema'
32
+ namespace 'com.my-namespace'
33
+ key_config field: 'test_id'
34
+ producer_class MyProducer
35
+ end
36
+ topic 'my-topic-with-id' do
37
+ schema 'MySchemaWithId'
38
+ namespace 'com.my-namespace'
39
+ key_config plain: true
40
+ producer_class MyProducerWithID
41
+ end
42
+ end
43
+
38
44
  end
39
45
 
40
46
  it 'should raise an error if no pollers configured' do
@@ -76,12 +82,7 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
76
82
  let(:config) { Deimos.config.db_poller_objects.first.dup }
77
83
 
78
84
  before(:each) do
79
- Widget.delete_all
80
85
  producer_class = Class.new(Deimos::ActiveRecordProducer) do
81
- schema 'MySchemaWithId'
82
- namespace 'com.my-namespace'
83
- topic 'my-topic-with-id'
84
- key_config none: true
85
86
  record_class Widget
86
87
 
87
88
  # :nodoc:
@@ -91,6 +92,16 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
91
92
  end
92
93
  stub_const('MyProducer', producer_class)
93
94
 
95
+ Widget.delete_all
96
+ Karafka::App.routes.redraw do
97
+ topic 'my-topic-with-id' do
98
+ schema 'MySchemaWithId'
99
+ namespace 'com.my-namespace'
100
+ key_config none: true
101
+ producer_class MyProducer
102
+ end
103
+ end
104
+
94
105
  Deimos.configure do
95
106
  db_poller do
96
107
  producer_class 'MyProducer'
@@ -195,7 +206,9 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
195
206
  before(:each) { config.skip_too_large_messages = true }
196
207
 
197
208
  it 'should skip and move on' do
198
- error = Kafka::MessageSizeTooLarge.new('OH NOES')
209
+ rdkafka_error = instance_double(Rdkafka::RdkafkaError, code: :msg_size_too_large)
210
+ error = WaterDrop::Errors::ProduceManyError.new(nil, nil)
211
+ allow(error).to receive(:cause).and_return(rdkafka_error)
199
212
  allow(poller).to receive(:sleep)
200
213
  allow(poller).to receive(:process_batch) do
201
214
  raise error
@@ -331,7 +344,7 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
331
344
  end
332
345
 
333
346
  it 'should send events across multiple batches' do
334
- allow(Deimos.config.logger).to receive(:info)
347
+ allow(Deimos::Logging).to receive(:log_info)
335
348
  allow(MyProducer).to receive(:poll_query).and_call_original
336
349
  expect(poller).to receive(:process_and_touch_info).ordered.
337
350
  with([widgets[0], widgets[1], widgets[2]], anything).and_call_original
@@ -376,7 +389,7 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
376
389
  time_to: time_value(secs: 120), # yes this is weird but it's because of travel_to
377
390
  column_name: :updated_at,
378
391
  min_id: last_widget.id)
379
- expect(Deimos.config.logger).to have_received(:info).
392
+ expect(Deimos::Logging).to have_received(:log_info).
380
393
  with('Poll MyProducer: ["my-topic-with-id"] complete at 2015-05-05 00:59:58 -0400 (3 batches, 0 errored batches, 7 processed messages)')
381
394
  end
382
395
 
@@ -398,7 +411,7 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
398
411
  describe 'errors' do
399
412
  before(:each) do
400
413
  poller.config.retries = 0
401
- allow(Deimos.config.logger).to receive(:info)
414
+ allow(Deimos::Logging).to receive(:log_info)
402
415
  end
403
416
 
404
417
  after(:each) do
@@ -428,7 +441,7 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
428
441
  info = Deimos::PollInfo.last
429
442
  expect(info.last_sent.in_time_zone).to eq(time_value(mins: -61, secs: 30))
430
443
  expect(info.last_sent_id).to eq(widgets[6].id)
431
- expect(Deimos.config.logger).to have_received(:info).
444
+ expect(Deimos::Logging).to have_received(:log_info).
432
445
  with('Poll MyProducer: ["my-topic-with-id"] complete at 2015-05-05 00:59:58 -0400 (2 batches, 1 errored batches, 7 processed messages)')
433
446
  end
434
447
  end
@@ -449,10 +462,6 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
449
462
  before(:each) do
450
463
  Widget.delete_all
451
464
  producer_class = Class.new(Deimos::ActiveRecordProducer) do
452
- schema 'MySchemaWithId'
453
- namespace 'com.my-namespace'
454
- topic 'my-topic-with-id'
455
- key_config none: true
456
465
  record_class Widget
457
466
 
458
467
  # :nodoc:
@@ -461,20 +470,22 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
461
470
  end
462
471
  end
463
472
  stub_const('ProducerOne', producer_class)
473
+ stub_const('ProducerTwo', producer_class)
464
474
 
465
- producer_class = Class.new(Deimos::ActiveRecordProducer) do
466
- schema 'MySchemaWithId'
467
- namespace 'com.my-namespace'
468
- topic 'my-topic-with-id'
469
- key_config none: true
470
- record_class Widget
471
-
472
- # :nodoc:
473
- def self.generate_payload(attrs, widget)
474
- super.merge(message_id: widget.generated_id)
475
+ Karafka::App.routes.redraw do
476
+ topic 'my-topic-with-id' do
477
+ schema 'MySchemaWithId'
478
+ namespace 'com.my-namespace'
479
+ key_config none: true
480
+ producer_class ProducerOne
481
+ end
482
+ topic 'my-topic-with-id2' do
483
+ schema 'MySchemaWithId'
484
+ namespace 'com.my-namespace'
485
+ key_config none: true
486
+ producer_class ProducerTwo
475
487
  end
476
488
  end
477
- stub_const('ProducerTwo', producer_class)
478
489
 
479
490
  poller_class = Class.new(Deimos::Utils::DbPoller::StateBased) do
480
491
  def self.producers
@@ -513,8 +524,7 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
513
524
  expect(Deimos::Utils::DbPoller::MultiProducerPoller).to receive(:poll_query).at_least(:once)
514
525
  poller.process_updates
515
526
 
516
- expect(ProducerOne).to have_received(:send_events).with(widgets)
517
- expect(ProducerTwo).to have_received(:send_events).with(widgets)
527
+ expect(ProducerOne).to have_received(:send_events).twice.with(widgets)
518
528
  expect(widgets.map(&:reload).map(&:publish_status)).to eq(%w(PUBLISHED PUBLISHED PUBLISHED))
519
529
  end
520
530
 
@@ -1,23 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- each_db_config(Deimos::Utils::DbProducer) do
3
+ each_db_config(Deimos::Utils::OutboxProducer) do
4
4
  let(:producer) do
5
5
  producer = described_class.new(logger)
6
6
  allow(producer).to receive(:sleep)
7
- allow(producer).to receive(:producer).and_return(phobos_producer)
8
7
  producer
9
8
  end
10
9
 
11
- let(:logger) { nil }
12
- let(:phobos_producer) do
13
- pp = instance_double(Phobos::Producer::PublicAPI)
14
- allow(pp).to receive(:publish_list)
15
- pp
16
- end
10
+ let(:logger) { instance_double(Logger, error: nil, info: nil, debug: nil )}
17
11
 
18
12
  before(:each) do
19
- stub_const('Deimos::Utils::DbProducer::BATCH_SIZE', 2)
20
- stub_const('Deimos::Utils::DbProducer::DELETE_BATCH_SIZE', 1)
13
+ stub_const('Deimos::Utils::OutboxProducer::BATCH_SIZE', 2)
14
+ stub_const('Deimos::Utils::OutboxProducer::DELETE_BATCH_SIZE', 1)
21
15
  end
22
16
 
23
17
  specify '#process_next_messages' do
@@ -47,7 +41,7 @@ each_db_config(Deimos::Utils::DbProducer) do
47
41
  message: 'blah',
48
42
  key: "key#{i}")
49
43
  end
50
- stub_const('Deimos::Utils::DbProducer::BATCH_SIZE', 5)
44
+ stub_const('Deimos::Utils::OutboxProducer::BATCH_SIZE', 5)
51
45
  producer.current_topic = 'topic1'
52
46
  messages = producer.retrieve_messages
53
47
  expect(messages.size).to eq(3)
@@ -58,71 +52,8 @@ each_db_config(Deimos::Utils::DbProducer) do
58
52
 
59
53
  it 'should produce normally' do
60
54
  batch = ['A'] * 1000
61
- expect(phobos_producer).to receive(:publish_list).with(batch).once
62
- expect(Deimos.config.metrics).to receive(:increment).with('publish',
63
- tags: %w(status:success topic:),
64
- by: 1000).once
65
- producer.produce_messages(batch)
66
- end
67
-
68
- it 'should split the batch size on buffer overflow' do
69
- class_producer = double(Phobos::Producer::ClassMethods::PublicAPI, # rubocop:disable RSpec/VerifiedDoubles
70
- sync_producer_shutdown: nil)
71
- allow(producer.class).to receive(:producer).and_return(class_producer)
72
- expect(class_producer).to receive(:sync_producer_shutdown).twice
73
- count = 0
74
- allow(phobos_producer).to receive(:publish_list) do
75
- count += 1
76
- raise Kafka::BufferOverflow if count < 3
77
- end
78
- allow(Deimos.config.metrics).to receive(:increment)
79
- batch = ['A'] * 1000
55
+ expect(Karafka.producer).to receive(:produce_many_sync).with(batch).once
80
56
  producer.produce_messages(batch)
81
- expect(phobos_producer).to have_received(:publish_list).with(batch)
82
- expect(phobos_producer).to have_received(:publish_list).with(['A'] * 100)
83
- expect(phobos_producer).to have_received(:publish_list).with(['A'] * 10).exactly(100).times
84
- expect(Deimos.config.metrics).to have_received(:increment).with('publish',
85
- tags: %w(status:success topic:),
86
- by: 10).exactly(100).times
87
- end
88
-
89
- it "should raise an error if it can't split any more" do
90
- allow(phobos_producer).to receive(:publish_list) do
91
- raise Kafka::BufferOverflow
92
- end
93
- expect(Deimos.config.metrics).not_to receive(:increment)
94
- batch = ['A'] * 1000
95
- expect { producer.produce_messages(batch) }.to raise_error(Kafka::BufferOverflow)
96
- expect(phobos_producer).to have_received(:publish_list).with(batch)
97
- expect(phobos_producer).to have_received(:publish_list).with(['A'] * 100).once
98
- expect(phobos_producer).to have_received(:publish_list).with(['A'] * 10).once
99
- expect(phobos_producer).to have_received(:publish_list).with(['A']).once
100
- end
101
-
102
- it 'should not resend batches of sent messages' do
103
- allow(phobos_producer).to receive(:publish_list) do |group|
104
- raise Kafka::BufferOverflow if group.any?('A') && group.size >= 1000
105
- raise Kafka::BufferOverflow if group.any?('BIG') && group.size >= 10
106
- end
107
- allow(Deimos.config.metrics).to receive(:increment)
108
- batch = ['A'] * 450 + ['BIG'] * 550
109
- producer.produce_messages(batch)
110
-
111
- expect(phobos_producer).to have_received(:publish_list).with(batch)
112
- expect(phobos_producer).to have_received(:publish_list).with(['A'] * 100).exactly(4).times
113
- expect(phobos_producer).to have_received(:publish_list).with(['A'] * 50 + ['BIG'] * 50)
114
- expect(phobos_producer).to have_received(:publish_list).with(['A'] * 10).exactly(5).times
115
- expect(phobos_producer).to have_received(:publish_list).with(['BIG'] * 1).exactly(550).times
116
-
117
- expect(Deimos.config.metrics).to have_received(:increment).with('publish',
118
- tags: %w(status:success topic:),
119
- by: 100).exactly(4).times
120
- expect(Deimos.config.metrics).to have_received(:increment).with('publish',
121
- tags: %w(status:success topic:),
122
- by: 10).exactly(5).times
123
- expect(Deimos.config.metrics).to have_received(:increment).with('publish',
124
- tags: %w(status:success topic:),
125
- by: 1).exactly(550).times
126
57
  end
127
58
 
128
59
  describe '#compact_messages' do
@@ -149,17 +80,17 @@ each_db_config(Deimos::Utils::DbProducer) do
149
80
  let(:deduped_batch) { batch[1..2] }
150
81
 
151
82
  it 'should dedupe messages when :all is set' do
152
- Deimos.configure { |c| c.db_producer.compact_topics = :all }
83
+ Deimos.configure { |c| c.outbox.compact_topics = :all }
153
84
  expect(producer.compact_messages(batch)).to eq(deduped_batch)
154
85
  end
155
86
 
156
87
  it 'should dedupe messages when topic is included' do
157
- Deimos.configure { |c| c.db_producer.compact_topics = %w(my-topic my-topic2) }
88
+ Deimos.configure { |c| c.outbox.compact_topics = %w(my-topic my-topic2) }
158
89
  expect(producer.compact_messages(batch)).to eq(deduped_batch)
159
90
  end
160
91
 
161
92
  it 'should not dedupe messages when topic is not included' do
162
- Deimos.configure { |c| c.db_producer.compact_topics = %w(my-topic3 my-topic2) }
93
+ Deimos.configure { |c| c.outbox.compact_topics = %w(my-topic3 my-topic2) }
163
94
  expect(producer.compact_messages(batch)).to eq(batch)
164
95
  end
165
96
 
@@ -176,13 +107,13 @@ each_db_config(Deimos::Utils::DbProducer) do
176
107
  message: 'BBB'
177
108
  }
178
109
  ].map { |h| Deimos::KafkaMessage.create!(h) }
179
- Deimos.configure { |c| c.db_producer.compact_topics = :all }
110
+ Deimos.configure { |c| c.outbox.compact_topics = :all }
180
111
  expect(producer.compact_messages(unkeyed_batch)).to eq(unkeyed_batch)
181
- Deimos.configure { |c| c.db_producer.compact_topics = [] }
112
+ Deimos.configure { |c| c.outbox.compact_topics = [] }
182
113
  end
183
114
 
184
115
  it 'should compact messages when all messages are unique' do
185
- Deimos.configure { |c| c.db_producer.compact_topics = %w(my-topic my-topic2) }
116
+ Deimos.configure { |c| c.outbox.compact_topics = %w(my-topic my-topic2) }
186
117
  expect(producer.compact_messages(deduped_batch)).to eq(deduped_batch)
187
118
  end
188
119
  end
@@ -228,7 +159,7 @@ each_db_config(Deimos::Utils::DbProducer) do
228
159
  }
229
160
  ])
230
161
  expect(Deimos.config.metrics).to receive(:increment).ordered.with(
231
- 'db_producer.process',
162
+ 'outbox.process',
232
163
  tags: %w(topic:my-topic),
233
164
  by: 2
234
165
  )
@@ -249,7 +180,7 @@ each_db_config(Deimos::Utils::DbProducer) do
249
180
  }
250
181
  ])
251
182
  expect(Deimos.config.metrics).to receive(:increment).ordered.with(
252
- 'db_producer.process',
183
+ 'outbox.process',
253
184
  tags: %w(topic:my-topic),
254
185
  by: 2
255
186
  )
@@ -263,13 +194,11 @@ each_db_config(Deimos::Utils::DbProducer) do
263
194
  end
264
195
 
265
196
  it 'should register an error if it gets an error' do
266
- allow(producer).to receive(:shutdown_producer)
267
197
  expect(producer).to receive(:retrieve_messages).and_raise('OH NOES')
268
198
  expect(Deimos::KafkaTopicInfo).to receive(:register_error).
269
199
  with('my-topic', 'abc')
270
200
  expect(producer).not_to receive(:produce_messages)
271
201
  producer.process_topic('my-topic')
272
- expect(producer).to have_received(:shutdown_producer)
273
202
  end
274
203
 
275
204
  it 'should move on if it gets a partial batch' do
@@ -299,14 +228,14 @@ each_db_config(Deimos::Utils::DbProducer) do
299
228
  expect(Deimos::KafkaTopicInfo).to receive(:register_error)
300
229
 
301
230
  expect(Deimos::KafkaMessage.count).to eq(4)
302
- subscriber = Deimos.subscribe('db_producer.produce') do |event|
231
+ Karafka.monitor.subscribe('deimos.outbox.produce') do |event|
303
232
  expect(event.payload[:exception_object].message).to eq('OH NOES')
304
233
  expect(event.payload[:messages]).to eq(messages)
305
234
  end
306
235
  producer.process_topic('my-topic')
307
236
  # don't delete for regular errors
308
237
  expect(Deimos::KafkaMessage.count).to eq(4)
309
- Deimos.unsubscribe(subscriber)
238
+ Karafka.monitor.notifications_bus.clear('deimos.outbox.produce')
310
239
  end
311
240
 
312
241
  it 'should retry deletes and not re-publish' do
@@ -340,7 +269,7 @@ each_db_config(Deimos::Utils::DbProducer) do
340
269
  with('my-topic', 'abc').and_return(true)
341
270
  expect(producer).to receive(:retrieve_messages).ordered.and_return(messages)
342
271
  expect(producer).to receive(:retrieve_messages).ordered.and_return([])
343
- expect(phobos_producer).to receive(:publish_list).once.with(messages.map(&:phobos_message))
272
+ expect(Karafka.producer).to receive(:produce_many_sync).once.with(messages.map(&:karafka_message))
344
273
 
345
274
  expect(Deimos::KafkaMessage.count).to eq(8)
346
275
  producer.process_topic('my-topic')
@@ -360,102 +289,6 @@ each_db_config(Deimos::Utils::DbProducer) do
360
289
  expect { producer.delete_messages(messages) }.to raise_exception('OH NOES')
361
290
  end
362
291
 
363
- context 'with buffer overflow exception' do
364
- let(:messages) do
365
- (1..4).map do |i|
366
- Deimos::KafkaMessage.create!(
367
- id: i,
368
- key: i,
369
- topic: 'my-topic',
370
- message: { message: "mess#{i}" },
371
- partition_key: "key#{i}"
372
- )
373
- end
374
- end
375
- let(:logger) do
376
- logger = instance_double(Logger)
377
- allow(logger).to receive(:error)
378
- logger
379
- end
380
- let(:message_producer) do
381
- Deimos.config.schema.backend = :mock
382
- Deimos::ActiveRecordProducer.topic('my-topic')
383
- Deimos::ActiveRecordProducer.key_config
384
- Deimos::ActiveRecordProducer
385
- end
386
-
387
- around(:each) do |example|
388
- config = Deimos::ActiveRecordProducer.config.clone
389
- backend = Deimos.config.schema.backend
390
-
391
- example.run
392
- ensure
393
- Deimos::ActiveRecordProducer.instance_variable_set(:@config, config)
394
- Deimos.config.schema.backend = backend
395
- end
396
-
397
- before(:each) do
398
- message_producer
399
- (5..8).each do |i|
400
- Deimos::KafkaMessage.create!(
401
- id: i,
402
- topic: 'my-topic2',
403
- message: "mess#{i}",
404
- partition_key: "key#{i}"
405
- )
406
- end
407
- allow(Deimos::KafkaTopicInfo).to receive(:lock).
408
- with('my-topic', 'abc').and_return(true)
409
- allow(producer).to receive(:produce_messages).and_raise(Kafka::BufferOverflow)
410
- allow(producer).to receive(:retrieve_messages).and_return(messages)
411
- allow(Deimos::KafkaTopicInfo).to receive(:register_error)
412
- end
413
-
414
- it 'should delete messages on buffer overflow' do
415
- expect(Deimos::KafkaMessage.count).to eq(8)
416
- producer.process_topic('my-topic')
417
- expect(Deimos::KafkaMessage.count).to eq(4)
418
- end
419
-
420
- it 'should notify on buffer overflow' do
421
- subscriber = Deimos.subscribe('db_producer.produce') do |event|
422
- expect(event.payload[:exception_object].message).to eq('Kafka::BufferOverflow')
423
- expect(event.payload[:messages]).to eq(messages)
424
- end
425
- producer.process_topic('my-topic')
426
- Deimos.unsubscribe(subscriber)
427
- expect(logger).to have_received(:error).with('Message batch too large, deleting...')
428
- expect(logger).to have_received(:error).with(
429
- [
430
- { key: '1', payload: 'payload-decoded' },
431
- { key: '2', payload: 'payload-decoded' },
432
- { key: '3', payload: 'payload-decoded' },
433
- { key: '4', payload: 'payload-decoded' }
434
- ]
435
- )
436
- end
437
-
438
- context 'with exception on error logging attempt' do
439
- let(:message_producer) do
440
- Deimos::ActiveRecordProducer.topic('my-topic')
441
- Deimos::ActiveRecordProducer
442
- end
443
-
444
- it 'should notify on buffer overflow disregarding decoding exception' do
445
- subscriber = Deimos.subscribe('db_producer.produce') do |event|
446
- expect(event.payload[:exception_object].message).to eq('Kafka::BufferOverflow')
447
- expect(event.payload[:messages]).to eq(messages)
448
- end
449
- producer.process_topic('my-topic')
450
- Deimos.unsubscribe(subscriber)
451
- expect(logger).to have_received(:error).with('Message batch too large, deleting...')
452
- expect(logger).to have_received(:error).with(
453
- 'Large message details logging failure: '\
454
- 'No key config given - if you are not decoding keys, please use `key_config plain: true`'
455
- )
456
- end
457
- end
458
- end
459
292
  end
460
293
 
461
294
  describe '#send_pending_metrics' do