deimos-ruby 1.24.1 → 1.24.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +3 -3
- data/.ruby-version +1 -2
- data/CHANGELOG.md +8 -0
- data/docs/CONFIGURATION.md +1 -0
- data/lib/deimos/active_record_consume/batch_consumption.rb +4 -2
- data/lib/deimos/active_record_consume/mass_updater.rb +59 -4
- data/lib/deimos/active_record_consumer.rb +5 -0
- data/lib/deimos/config/configuration.rb +7 -1
- data/lib/deimos/config/phobos_config.rb +2 -1
- data/lib/deimos/kafka_topic_info.rb +7 -2
- data/lib/deimos/version.rb +1 -1
- data/spec/active_record_consume/mass_updater_spec.rb +137 -0
- data/spec/config/configuration_spec.rb +13 -5
- data/spec/spec_helper.rb +2 -0
- metadata +2 -3
- data/.circleci/config.yml +0 -83
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de8ca3bf7233f799c3bf9169fa647dabebd8e08cd2b05ec00511c132a5f3920d
|
|
4
|
+
data.tar.gz: 03177d9ac87184fe3ce6ef916bce0ad39e3b81a6576f60ba71c33b298f82dfd8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 40ecdddd9c0b8f5f9675f8058f4a8c8adf1eb69a293e04870a46b9d8ae1972cdc70088611c898f0ab91e072f6627c4760bca5ca5399b698316edda8f3212f5aa
|
|
7
|
+
data.tar.gz: 3f2fa463d5c777ce7e4dfc4cf610a7dd4ed3f6dba5b6dd459f1ca8fad037f0baa47278436c65c91dc90679f88e9d42a792b84ccbdc2cde4b58d1239d03b2fd4a
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -19,10 +19,10 @@ jobs:
|
|
|
19
19
|
steps:
|
|
20
20
|
- uses: actions/checkout@v3
|
|
21
21
|
|
|
22
|
-
- name: Set up Ruby
|
|
22
|
+
- name: Set up Ruby 3.3
|
|
23
23
|
uses: ruby/setup-ruby@v1
|
|
24
24
|
with:
|
|
25
|
-
ruby-version:
|
|
25
|
+
ruby-version: 3.3
|
|
26
26
|
bundler-cache: true
|
|
27
27
|
|
|
28
28
|
- name: Bundle install
|
|
@@ -36,7 +36,7 @@ jobs:
|
|
|
36
36
|
strategy:
|
|
37
37
|
fail-fast: false
|
|
38
38
|
matrix:
|
|
39
|
-
ruby: [ '2.
|
|
39
|
+
ruby: [ '2.7', '3.0', '3.1', '3.2', '3.3' ]
|
|
40
40
|
|
|
41
41
|
steps:
|
|
42
42
|
- uses: actions/checkout@v3
|
data/.ruby-version
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
2.
|
|
2
|
-
|
|
1
|
+
3.2.2
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## UNRELEASED
|
|
9
9
|
|
|
10
|
+
# 1.24.3 - 2024-05-13
|
|
11
|
+
|
|
12
|
+
- Feature: Enable `producers.persistent_connections` phobos setting
|
|
13
|
+
- Feature: Add consumer configuration, `save_associations_first` to save associated records of primary class prior to upserting primary records. Foreign key of associated records are assigned to the record class prior to saving the record class
|
|
14
|
+
|
|
15
|
+
# 1.24.2 - 2024-05-01
|
|
16
|
+
- Fix: Deprecation notice with Rails 7.
|
|
17
|
+
|
|
10
18
|
# 1.24.1 - 2024-03-26
|
|
11
19
|
- Fix: ActiveRecordConsumer batch consumption was not working with the trilogy adapter.
|
|
12
20
|
|
data/docs/CONFIGURATION.md
CHANGED
|
@@ -102,6 +102,7 @@ heartbeat_interval|10|Interval between heartbeats; must be less than the session
|
|
|
102
102
|
backoff|`(1000..60_000)`|Range representing the minimum and maximum number of milliseconds to back off after a consumer error.
|
|
103
103
|
replace_associations|nil| Whether to delete existing associations for records during bulk consumption for this consumer. If no value is specified the provided/default value from the `consumers` configuration will be used.
|
|
104
104
|
bulk_import_id_generator|nil| Block to determine the `bulk_import_id` generated during bulk consumption. If no block is specified the provided/default block from the `consumers` configuration will be used.
|
|
105
|
+
save_associations_first|false|Whether to save associated records of primary class prior to upserting primary records. Foreign key of associated records are assigned to the record class prior to saving the record class
|
|
105
106
|
|
|
106
107
|
## Defining Database Pollers
|
|
107
108
|
|
|
@@ -83,7 +83,7 @@ module Deimos
|
|
|
83
83
|
def deleted_query(records)
|
|
84
84
|
keys = records.
|
|
85
85
|
map { |m| record_key(m.key)[@klass.primary_key] }.
|
|
86
|
-
|
|
86
|
+
compact
|
|
87
87
|
|
|
88
88
|
@klass.unscoped.where(@klass.primary_key => keys)
|
|
89
89
|
end
|
|
@@ -168,7 +168,9 @@ module Deimos
|
|
|
168
168
|
key_col_proc: key_col_proc,
|
|
169
169
|
col_proc: col_proc,
|
|
170
170
|
replace_associations: self.class.replace_associations,
|
|
171
|
-
bulk_import_id_generator: self.class.bulk_import_id_generator
|
|
171
|
+
bulk_import_id_generator: self.class.bulk_import_id_generator,
|
|
172
|
+
save_associations_first: self.class.save_associations_first,
|
|
173
|
+
bulk_import_id_column: self.class.bulk_import_id_column)
|
|
172
174
|
ActiveSupport::Notifications.instrument('batch_consumption.valid_records', {
|
|
173
175
|
records: updater.mass_update(record_list),
|
|
174
176
|
consumer: self.class
|
|
@@ -20,10 +20,13 @@ module Deimos
|
|
|
20
20
|
# @param col_proc [Proc<Class < ActiveRecord::Base>]
|
|
21
21
|
# @param replace_associations [Boolean]
|
|
22
22
|
def initialize(klass, key_col_proc: nil, col_proc: nil,
|
|
23
|
-
replace_associations: true, bulk_import_id_generator: nil
|
|
23
|
+
replace_associations: true, bulk_import_id_generator: nil, save_associations_first: false,
|
|
24
|
+
bulk_import_id_column: nil)
|
|
24
25
|
@klass = klass
|
|
25
26
|
@replace_associations = replace_associations
|
|
26
27
|
@bulk_import_id_generator = bulk_import_id_generator
|
|
28
|
+
@save_associations_first = save_associations_first
|
|
29
|
+
@bulk_import_id_column = bulk_import_id_column&.to_s
|
|
27
30
|
|
|
28
31
|
@key_cols = {}
|
|
29
32
|
@key_col_proc = key_col_proc
|
|
@@ -84,15 +87,67 @@ module Deimos
|
|
|
84
87
|
end
|
|
85
88
|
end
|
|
86
89
|
|
|
90
|
+
# Assign associated records to corresponding primary records
|
|
91
|
+
# @param record_list [BatchRecordList] RecordList of primary records for this consumer
|
|
92
|
+
# @return [Hash]
|
|
93
|
+
def assign_associations(record_list)
|
|
94
|
+
associations_info = {}
|
|
95
|
+
record_list.associations.each do |assoc|
|
|
96
|
+
col = @bulk_import_id_column if assoc.klass.column_names.include?(@bulk_import_id_column)
|
|
97
|
+
associations_info[[assoc, col]] = []
|
|
98
|
+
end
|
|
99
|
+
record_list.batch_records.each do |primary_batch_record|
|
|
100
|
+
associations_info.each_key do |assoc, col|
|
|
101
|
+
batch_record = BatchRecord.new(klass: assoc.klass,
|
|
102
|
+
attributes: primary_batch_record.associations[assoc.name],
|
|
103
|
+
bulk_import_column: col,
|
|
104
|
+
bulk_import_id_generator: @bulk_import_id_generator)
|
|
105
|
+
# Associate this associated batch record's record with the primary record to
|
|
106
|
+
# retrieve foreign_key after associated records have been saved and primary
|
|
107
|
+
# keys have been filled
|
|
108
|
+
primary_batch_record.record.assign_attributes({ assoc.name => batch_record.record })
|
|
109
|
+
associations_info[[assoc, col]] << batch_record
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
associations_info
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Save associated records and fill foreign keys on RecordList records
|
|
116
|
+
# @param record_list [BatchRecordList] RecordList of primary records for this consumer
|
|
117
|
+
# @param associations_info [Hash] Contains association info
|
|
118
|
+
def save_associations_first(record_list, associations_info)
|
|
119
|
+
associations_info.each_value do |records|
|
|
120
|
+
assoc_record_list = BatchRecordList.new(records)
|
|
121
|
+
Deimos::Utils::DeadlockRetry.wrap(Deimos.config.tracer.active_span.get_tag('topic')) do
|
|
122
|
+
save_records_to_database(assoc_record_list)
|
|
123
|
+
end
|
|
124
|
+
import_associations(assoc_record_list)
|
|
125
|
+
end
|
|
126
|
+
record_list.records.each do |record|
|
|
127
|
+
associations_info.each_key do |assoc, _|
|
|
128
|
+
record.assign_attributes({ assoc.foreign_key => record.send(assoc.name).id })
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
87
133
|
# @param record_list [BatchRecordList]
|
|
88
134
|
# @return [Array<ActiveRecord::Base>]
|
|
89
135
|
def mass_update(record_list)
|
|
90
136
|
# The entire batch should be treated as one transaction so that if
|
|
91
137
|
# any message fails, the whole thing is rolled back or retried
|
|
92
138
|
# if there is deadlock
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
139
|
+
|
|
140
|
+
if @save_associations_first
|
|
141
|
+
associations_info = assign_associations(record_list)
|
|
142
|
+
save_associations_first(record_list, associations_info)
|
|
143
|
+
Deimos::Utils::DeadlockRetry.wrap(Deimos.config.tracer.active_span.get_tag('topic')) do
|
|
144
|
+
save_records_to_database(record_list)
|
|
145
|
+
end
|
|
146
|
+
else
|
|
147
|
+
Deimos::Utils::DeadlockRetry.wrap(Deimos.config.tracer.active_span.get_tag('topic')) do
|
|
148
|
+
save_records_to_database(record_list)
|
|
149
|
+
import_associations(record_list) if record_list.associations.any?
|
|
150
|
+
end
|
|
96
151
|
end
|
|
97
152
|
record_list.records
|
|
98
153
|
end
|
|
@@ -45,6 +45,11 @@ module Deimos
|
|
|
45
45
|
config[:replace_associations]
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
# @return [Boolean]
|
|
49
|
+
def save_associations_first
|
|
50
|
+
config[:save_associations_first]
|
|
51
|
+
end
|
|
52
|
+
|
|
48
53
|
# @param val [Boolean] Turn pre-compaction of the batch on or off. If true,
|
|
49
54
|
# only the last message for each unique key in a batch is processed.
|
|
50
55
|
# @return [void]
|
|
@@ -97,7 +97,8 @@ module Deimos # rubocop:disable Metrics/ModuleLength
|
|
|
97
97
|
kafka_config.replace_associations
|
|
98
98
|
end,
|
|
99
99
|
bulk_import_id_generator: kafka_config.bulk_import_id_generator ||
|
|
100
|
-
Deimos.config.consumers.bulk_import_id_generator
|
|
100
|
+
Deimos.config.consumers.bulk_import_id_generator,
|
|
101
|
+
save_associations_first: kafka_config.save_associations_first
|
|
101
102
|
)
|
|
102
103
|
end
|
|
103
104
|
end
|
|
@@ -476,6 +477,11 @@ module Deimos # rubocop:disable Metrics/ModuleLength
|
|
|
476
477
|
# @return [Block]
|
|
477
478
|
setting :bulk_import_id_generator, nil
|
|
478
479
|
|
|
480
|
+
# If enabled save associated records prior to saving the main record class
|
|
481
|
+
# This will also set foreign keys for associated records
|
|
482
|
+
# @return [Boolean]
|
|
483
|
+
setting :save_associations_first, false
|
|
484
|
+
|
|
479
485
|
# These are the phobos "listener" configs. See CONFIGURATION.md for more
|
|
480
486
|
# info.
|
|
481
487
|
setting :group_id
|
|
@@ -52,7 +52,8 @@ module Deimos
|
|
|
52
52
|
compression_threshold: self.producers.compression_threshold,
|
|
53
53
|
max_queue_size: self.producers.max_queue_size,
|
|
54
54
|
delivery_threshold: self.producers.delivery_threshold,
|
|
55
|
-
delivery_interval: self.producers.delivery_interval
|
|
55
|
+
delivery_interval: self.producers.delivery_interval,
|
|
56
|
+
persistent_connections: self.producers.persistent_connections
|
|
56
57
|
},
|
|
57
58
|
consumer: {
|
|
58
59
|
session_timeout: self.consumers.session_timeout,
|
|
@@ -6,6 +6,11 @@ module Deimos
|
|
|
6
6
|
self.table_name = 'kafka_topic_info'
|
|
7
7
|
|
|
8
8
|
class << self
|
|
9
|
+
|
|
10
|
+
def quote_time(time)
|
|
11
|
+
time.respond_to?(:to_fs) ? time.to_fs(:db) : time.to_s(:db)
|
|
12
|
+
end
|
|
13
|
+
|
|
9
14
|
# Lock a topic for the given ID. Returns whether the lock was successful.
|
|
10
15
|
# @param topic [String]
|
|
11
16
|
# @param lock_id [String]
|
|
@@ -22,9 +27,9 @@ module Deimos
|
|
|
22
27
|
qtopic = self.connection.quote(topic)
|
|
23
28
|
qlock_id = self.connection.quote(lock_id)
|
|
24
29
|
qtable = self.connection.quote_table_name('kafka_topic_info')
|
|
25
|
-
qnow = self.connection.quote(Time.zone.now
|
|
30
|
+
qnow = self.connection.quote(quote_time(Time.zone.now))
|
|
26
31
|
qfalse = self.connection.quoted_false
|
|
27
|
-
qtime = self.connection.quote(1.minute.ago
|
|
32
|
+
qtime = self.connection.quote(quote_time(1.minute.ago))
|
|
28
33
|
|
|
29
34
|
# If a record is marked as error and less than 1 minute old,
|
|
30
35
|
# we don't want to pick it up even if not currently locked because
|
data/lib/deimos/version.rb
CHANGED
|
@@ -114,5 +114,142 @@ RSpec.describe Deimos::ActiveRecordConsume::MassUpdater do
|
|
|
114
114
|
|
|
115
115
|
end
|
|
116
116
|
|
|
117
|
+
context 'with save_associations_first' do
|
|
118
|
+
before(:all) do
|
|
119
|
+
ActiveRecord::Base.connection.create_table(:fidgets, force: true) do |t|
|
|
120
|
+
t.string(:test_id)
|
|
121
|
+
t.integer(:some_int)
|
|
122
|
+
t.string(:bulk_import_id)
|
|
123
|
+
t.timestamps
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
ActiveRecord::Base.connection.create_table(:fidget_details, force: true) do |t|
|
|
127
|
+
t.string(:title)
|
|
128
|
+
t.string(:bulk_import_id)
|
|
129
|
+
t.belongs_to(:fidget)
|
|
130
|
+
|
|
131
|
+
t.index(%i(title), unique: true)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
ActiveRecord::Base.connection.create_table(:widget_fidgets, force: true, id: false) do |t|
|
|
135
|
+
t.belongs_to(:fidget)
|
|
136
|
+
t.belongs_to(:widget)
|
|
137
|
+
t.string(:bulk_import_id)
|
|
138
|
+
t.string(:note)
|
|
139
|
+
t.index(%i(widget_id fidget_id), unique: true)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
after(:all) do
|
|
144
|
+
ActiveRecord::Base.connection.drop_table(:fidgets)
|
|
145
|
+
ActiveRecord::Base.connection.drop_table(:fidget_details)
|
|
146
|
+
ActiveRecord::Base.connection.drop_table(:widget_fidgets)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
let(:fidget_detail_class) do
|
|
150
|
+
Class.new(ActiveRecord::Base) do
|
|
151
|
+
self.table_name = 'fidget_details'
|
|
152
|
+
belongs_to :fidget
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
let(:fidget_class) do
|
|
157
|
+
Class.new(ActiveRecord::Base) do
|
|
158
|
+
self.table_name = 'fidgets'
|
|
159
|
+
has_one :fidget_detail
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
let(:widget_fidget_class) do
|
|
164
|
+
Class.new(ActiveRecord::Base) do
|
|
165
|
+
self.table_name = 'widget_fidgets'
|
|
166
|
+
belongs_to :fidget
|
|
167
|
+
belongs_to :widget
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
let(:bulk_id_generator) { proc { SecureRandom.uuid } }
|
|
172
|
+
|
|
173
|
+
let(:key_proc) do
|
|
174
|
+
lambda do |klass|
|
|
175
|
+
case klass.to_s
|
|
176
|
+
when 'Widget', 'Fidget'
|
|
177
|
+
%w(id)
|
|
178
|
+
when 'WidgetFidget'
|
|
179
|
+
%w(widget_id fidget_id)
|
|
180
|
+
when 'FidgetDetail', 'Detail'
|
|
181
|
+
%w(title)
|
|
182
|
+
else
|
|
183
|
+
raise "Key Columns for #{klass} not defined"
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
before(:each) do
|
|
190
|
+
stub_const('Fidget', fidget_class)
|
|
191
|
+
stub_const('FidgetDetail', fidget_detail_class)
|
|
192
|
+
stub_const('WidgetFidget', widget_fidget_class)
|
|
193
|
+
Widget.reset_column_information
|
|
194
|
+
Fidget.reset_column_information
|
|
195
|
+
WidgetFidget.reset_column_information
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# rubocop:disable RSpec/MultipleExpectations, RSpec/ExampleLength
|
|
199
|
+
it 'should backfill the associations when upserting primary records' do
|
|
200
|
+
batch = Deimos::ActiveRecordConsume::BatchRecordList.new(
|
|
201
|
+
[
|
|
202
|
+
Deimos::ActiveRecordConsume::BatchRecord.new(
|
|
203
|
+
klass: WidgetFidget,
|
|
204
|
+
attributes: {
|
|
205
|
+
widget: { test_id: 'id1', some_int: 10, detail: { title: 'Widget Title 1' } },
|
|
206
|
+
fidget: { test_id: 'id1', some_int: 10, fidget_detail: { title: 'Fidget Title 1' } },
|
|
207
|
+
note: 'Stuff 1'
|
|
208
|
+
},
|
|
209
|
+
bulk_import_column: 'bulk_import_id',
|
|
210
|
+
bulk_import_id_generator: bulk_id_generator
|
|
211
|
+
),
|
|
212
|
+
Deimos::ActiveRecordConsume::BatchRecord.new(
|
|
213
|
+
klass: WidgetFidget,
|
|
214
|
+
attributes: {
|
|
215
|
+
widget: { test_id: 'id2', some_int: 20, detail: { title: 'Widget Title 2' } },
|
|
216
|
+
fidget: { test_id: 'id2', some_int: 20, fidget_detail: { title: 'Fidget Title 2' } },
|
|
217
|
+
note: 'Stuff 2'
|
|
218
|
+
},
|
|
219
|
+
bulk_import_column: 'bulk_import_id',
|
|
220
|
+
bulk_import_id_generator: bulk_id_generator
|
|
221
|
+
)
|
|
222
|
+
]
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
results = described_class.new(WidgetFidget,
|
|
226
|
+
bulk_import_id_generator: bulk_id_generator,
|
|
227
|
+
bulk_import_id_column: 'bulk_import_id',
|
|
228
|
+
key_col_proc: key_proc,
|
|
229
|
+
save_associations_first: true).mass_update(batch)
|
|
230
|
+
expect(results.count).to eq(2)
|
|
231
|
+
expect(Widget.count).to eq(2)
|
|
232
|
+
expect(Detail.count).to eq(2)
|
|
233
|
+
expect(Fidget.count).to eq(2)
|
|
234
|
+
expect(FidgetDetail.count).to eq(2)
|
|
235
|
+
|
|
236
|
+
WidgetFidget.all.each_with_index do |widget_fidget, ind|
|
|
237
|
+
widget = Widget.find_by(id: widget_fidget.widget_id)
|
|
238
|
+
expect(widget.test_id).to eq("id#{ind + 1}")
|
|
239
|
+
expect(widget.some_int).to eq((ind + 1) * 10)
|
|
240
|
+
detail = Detail.find_by(widget_id: widget_fidget.widget_id)
|
|
241
|
+
expect(detail.title).to eq("Widget Title #{ind + 1}")
|
|
242
|
+
fidget = Fidget.find_by(id: widget_fidget.fidget_id)
|
|
243
|
+
expect(fidget.test_id).to eq("id#{ind + 1}")
|
|
244
|
+
expect(fidget.some_int).to eq((ind + 1) * 10)
|
|
245
|
+
fidget_detail = FidgetDetail.find_by(fidget_id: widget_fidget.fidget_id)
|
|
246
|
+
expect(fidget_detail.title).to eq("Fidget Title #{ind + 1}")
|
|
247
|
+
expect(widget_fidget.note).to eq("Stuff #{ind + 1}")
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
# rubocop:enable RSpec/MultipleExpectations, RSpec/ExampleLength
|
|
251
|
+
|
|
252
|
+
end
|
|
253
|
+
|
|
117
254
|
end
|
|
118
255
|
end
|
|
@@ -92,7 +92,8 @@ describe Deimos, 'configuration' do
|
|
|
92
92
|
handler: 'ConsumerTest::MyConsumer',
|
|
93
93
|
use_schema_classes: nil,
|
|
94
94
|
max_db_batch_size: nil,
|
|
95
|
-
bulk_import_id_generator: nil
|
|
95
|
+
bulk_import_id_generator: nil,
|
|
96
|
+
save_associations_first: false
|
|
96
97
|
}, {
|
|
97
98
|
topic: 'my_batch_consume_topic',
|
|
98
99
|
group_id: 'my_batch_group_id',
|
|
@@ -111,7 +112,8 @@ describe Deimos, 'configuration' do
|
|
|
111
112
|
handler: 'ConsumerTest::MyBatchConsumer',
|
|
112
113
|
use_schema_classes: nil,
|
|
113
114
|
max_db_batch_size: nil,
|
|
114
|
-
bulk_import_id_generator: nil
|
|
115
|
+
bulk_import_id_generator: nil,
|
|
116
|
+
save_associations_first: false
|
|
115
117
|
}
|
|
116
118
|
],
|
|
117
119
|
producer: {
|
|
@@ -125,7 +127,8 @@ describe Deimos, 'configuration' do
|
|
|
125
127
|
compression_threshold: 1,
|
|
126
128
|
max_queue_size: 10_000,
|
|
127
129
|
delivery_threshold: 0,
|
|
128
|
-
delivery_interval: 0
|
|
130
|
+
delivery_interval: 0,
|
|
131
|
+
persistent_connections: false
|
|
129
132
|
}
|
|
130
133
|
)
|
|
131
134
|
end
|
|
@@ -264,7 +267,8 @@ describe Deimos, 'configuration' do
|
|
|
264
267
|
handler: 'MyConfigConsumer',
|
|
265
268
|
use_schema_classes: false,
|
|
266
269
|
max_db_batch_size: nil,
|
|
267
|
-
bulk_import_id_generator: nil
|
|
270
|
+
bulk_import_id_generator: nil,
|
|
271
|
+
save_associations_first: false
|
|
268
272
|
}
|
|
269
273
|
],
|
|
270
274
|
producer: {
|
|
@@ -278,7 +282,8 @@ describe Deimos, 'configuration' do
|
|
|
278
282
|
compression_threshold: 2,
|
|
279
283
|
max_queue_size: 10,
|
|
280
284
|
delivery_threshold: 1,
|
|
281
|
-
delivery_interval: 1
|
|
285
|
+
delivery_interval: 1,
|
|
286
|
+
persistent_connections: true
|
|
282
287
|
}
|
|
283
288
|
)
|
|
284
289
|
end
|
|
@@ -295,6 +300,7 @@ describe Deimos, 'configuration' do
|
|
|
295
300
|
group_id 'myconsumerid'
|
|
296
301
|
bulk_import_id_generator(-> { 'consumer' })
|
|
297
302
|
replace_associations false
|
|
303
|
+
save_associations_first true
|
|
298
304
|
end
|
|
299
305
|
|
|
300
306
|
consumer do
|
|
@@ -312,10 +318,12 @@ describe Deimos, 'configuration' do
|
|
|
312
318
|
custom = MyConfigConsumer.config
|
|
313
319
|
expect(custom[:replace_associations]).to eq(false)
|
|
314
320
|
expect(custom[:bulk_import_id_generator].call).to eq('consumer')
|
|
321
|
+
expect(custom[:save_associations_first]).to eq(true)
|
|
315
322
|
|
|
316
323
|
default = MyConfigConsumer2.config
|
|
317
324
|
expect(default[:replace_associations]).to eq(true)
|
|
318
325
|
expect(default[:bulk_import_id_generator].call).to eq('global')
|
|
326
|
+
expect(default[:save_associations_first]).to eq(false)
|
|
319
327
|
|
|
320
328
|
end
|
|
321
329
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -14,6 +14,8 @@ require 'handlers/my_batch_consumer'
|
|
|
14
14
|
require 'handlers/my_consumer'
|
|
15
15
|
require 'rspec/rails'
|
|
16
16
|
require 'rspec/snapshot'
|
|
17
|
+
require "trilogy_adapter/connection"
|
|
18
|
+
ActiveRecord::Base.public_send :extend, TrilogyAdapter::Connection
|
|
17
19
|
Dir['./spec/schemas/**/*.rb'].sort.each { |f| require f }
|
|
18
20
|
|
|
19
21
|
# Constants used for consumer specs
|
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.24.
|
|
4
|
+
version: 1.24.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Orner
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-
|
|
11
|
+
date: 2024-05-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: avro_turf
|
|
@@ -415,7 +415,6 @@ executables:
|
|
|
415
415
|
extensions: []
|
|
416
416
|
extra_rdoc_files: []
|
|
417
417
|
files:
|
|
418
|
-
- ".circleci/config.yml"
|
|
419
418
|
- ".github/workflows/ci.yml"
|
|
420
419
|
- ".gitignore"
|
|
421
420
|
- ".gitmodules"
|
data/.circleci/config.yml
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
defaults: &defaults
|
|
2
|
-
parallelism: 1
|
|
3
|
-
working_directory: ~/workspace
|
|
4
|
-
docker:
|
|
5
|
-
- image: ruby:2.6
|
|
6
|
-
environment:
|
|
7
|
-
RAILS_ENV: test
|
|
8
|
-
DB_HOST_IP: 127.0.0.1
|
|
9
|
-
version: 2.1
|
|
10
|
-
jobs:
|
|
11
|
-
build:
|
|
12
|
-
<<: *defaults
|
|
13
|
-
steps:
|
|
14
|
-
- checkout
|
|
15
|
-
|
|
16
|
-
# Restore bundle cache & npm cache
|
|
17
|
-
- restore_cache:
|
|
18
|
-
key: 'rails-{{ checksum "Gemfile.lock" }}'
|
|
19
|
-
|
|
20
|
-
# Bundle install dependencies in /tmp/
|
|
21
|
-
# so Dockerfile does not copy them since
|
|
22
|
-
# its base image is different than CircleCI
|
|
23
|
-
- run:
|
|
24
|
-
name: Install bundler
|
|
25
|
-
command: gem install bundler:2.1.4
|
|
26
|
-
- run:
|
|
27
|
-
name: Bundle install
|
|
28
|
-
command: bundle install --path vendor/bundle --jobs=4 --retry=3
|
|
29
|
-
|
|
30
|
-
# Store bundle cache
|
|
31
|
-
- save_cache:
|
|
32
|
-
key: 'rails-{{ checksum "Gemfile.lock" }}'
|
|
33
|
-
paths:
|
|
34
|
-
- ~/workspace/vendor/bundle
|
|
35
|
-
|
|
36
|
-
- persist_to_workspace:
|
|
37
|
-
root: ~/workspace
|
|
38
|
-
paths:
|
|
39
|
-
- .
|
|
40
|
-
|
|
41
|
-
lint:
|
|
42
|
-
<<: *defaults
|
|
43
|
-
steps:
|
|
44
|
-
- attach_workspace:
|
|
45
|
-
at: ~/workspace
|
|
46
|
-
- run:
|
|
47
|
-
name: Install bundler
|
|
48
|
-
command: gem install bundler:2.1.4
|
|
49
|
-
- run:
|
|
50
|
-
name: Point bundle to vendor/bundle
|
|
51
|
-
command: bundle --path vendor/bundle
|
|
52
|
-
- run: bundle exec rubocop --display-only-fail-level-offenses --fail-level C
|
|
53
|
-
|
|
54
|
-
test-rspec:
|
|
55
|
-
<<: *defaults
|
|
56
|
-
steps:
|
|
57
|
-
- attach_workspace:
|
|
58
|
-
at: ~/workspace
|
|
59
|
-
- run:
|
|
60
|
-
name: Install bundler
|
|
61
|
-
command: gem install bundler:2.1.4
|
|
62
|
-
- run:
|
|
63
|
-
name: Point bundle to vendor/bundle
|
|
64
|
-
command: bundle --path vendor/bundle
|
|
65
|
-
- run: mkdir result
|
|
66
|
-
- run:
|
|
67
|
-
name: Running rspec
|
|
68
|
-
command: bundle exec rspec --format progress --format RspecJunitFormatter -o result/rspec.xml
|
|
69
|
-
when: always
|
|
70
|
-
- store_test_results:
|
|
71
|
-
path: ~/workspace/result
|
|
72
|
-
|
|
73
|
-
workflows:
|
|
74
|
-
version: 2
|
|
75
|
-
build-and-test:
|
|
76
|
-
jobs:
|
|
77
|
-
- build
|
|
78
|
-
- test-rspec:
|
|
79
|
-
requires:
|
|
80
|
-
- build
|
|
81
|
-
- lint:
|
|
82
|
-
requires:
|
|
83
|
-
- build
|