deimos-ruby 2.5.0 → 2.5.2
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/CHANGELOG.md +8 -0
- data/lib/deimos/active_record_consume/batch_record.rb +3 -0
- data/lib/deimos/active_record_consume/batch_record_list.rb +2 -1
- data/lib/deimos/kafka_topic_info.rb +1 -1
- data/lib/deimos/version.rb +1 -1
- data/spec/active_record_consume/mass_updater_spec.rb +28 -0
- data/spec/kafka_topic_info_spec.rb +5 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 705269764ba0122cc1eff515eef044d8855b2b050c0e4ad29627c65055da8e66
|
|
4
|
+
data.tar.gz: 6184e80be2db0d657b47fd2d4a54957b95ce52f3c40eeee0edafa59d7de99c96
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 608942a3b72c7f5da730349d19da526582a564f9ffdb66e3c2a3b9bfe63821ce575b87e663aeaf341879fb2887a48927dbae496b8068b61ff6e32e23ca650cdd
|
|
7
|
+
data.tar.gz: 393aa82894d78399130fd3aed4ae46794dd3879cb6c52f992f4f8e11ff2e1febde69a68f3d9e18b7360c6fd6ab298b823ed69e32ae41231e299e6b96e28eecfc
|
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
|
+
## 2.5.2 - 2026-04-24
|
|
11
|
+
|
|
12
|
+
- Fix: `BatchRecordList#fill_primary_keys!` no longer short-circuits on stale in-memory primary keys left over from a rolled-back `DeadlockRetry` attempt, preventing `ActiveRecord::InvalidForeignKey` during association imports.
|
|
13
|
+
|
|
14
|
+
## 2.5.1 - 2026-03-18
|
|
15
|
+
|
|
16
|
+
- Fix: Outbox producer would swallow ActiveRecord errors except for uniqueness.
|
|
17
|
+
|
|
10
18
|
## 2.5.0 - 2026-03-04
|
|
11
19
|
|
|
12
20
|
- Breaking: `process_message?` in batch consumption now receives the full Kafka message object instead of just the payload, allowing tombstones to be identified via the message key and metadata.
|
|
@@ -16,6 +16,8 @@ module Deimos
|
|
|
16
16
|
attr_accessor :bulk_import_id
|
|
17
17
|
# @return [String] The column name to use for bulk IDs - defaults to `bulk_import_id`.
|
|
18
18
|
attr_accessor :bulk_import_column
|
|
19
|
+
# @return [Boolean] true if the primary key was supplied in the input attributes,
|
|
20
|
+
attr_accessor :primary_key_preset
|
|
19
21
|
|
|
20
22
|
delegate :valid?, :errors, :send, :attributes, to: :record
|
|
21
23
|
|
|
@@ -32,6 +34,7 @@ module Deimos
|
|
|
32
34
|
end
|
|
33
35
|
attributes = attributes.with_indifferent_access
|
|
34
36
|
self.record = klass.new(attributes.slice(*klass.column_names))
|
|
37
|
+
self.primary_key_preset = !self.record[klass.primary_key].nil?
|
|
35
38
|
assoc_keys = attributes.keys.select { |k| klass.reflect_on_association(k) }
|
|
36
39
|
# a hash with just the association keys, removing all actual column information.
|
|
37
40
|
self.associations = attributes.slice(*assoc_keys)
|
|
@@ -53,7 +53,8 @@ module Deimos
|
|
|
53
53
|
def fill_primary_keys!
|
|
54
54
|
primary_col = self.klass.primary_key
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
# Skip if nothing to backfill or caller already supplied the PK.
|
|
57
|
+
return if self.batch_records.empty? || self.batch_records.first.primary_key_preset
|
|
57
58
|
|
|
58
59
|
bulk_import_map = self.klass.
|
|
59
60
|
where(self.bulk_import_column => self.batch_records.map(&:bulk_import_id)).
|
|
@@ -18,7 +18,7 @@ module Deimos
|
|
|
18
18
|
def lock(topic, lock_id) # rubocop:disable Naming/PredicateMethod
|
|
19
19
|
# Try to create it - it's fine if it already exists
|
|
20
20
|
begin
|
|
21
|
-
self.create(topic: topic, last_processed_at: Time.zone.now)
|
|
21
|
+
self.create!(topic: topic, last_processed_at: Time.zone.now)
|
|
22
22
|
rescue ActiveRecord::RecordNotUnique
|
|
23
23
|
# continue on
|
|
24
24
|
end
|
data/lib/deimos/version.rb
CHANGED
|
@@ -112,6 +112,34 @@ RSpec.describe Deimos::ActiveRecordConsume::MassUpdater do
|
|
|
112
112
|
expect(Detail.count).to eq(0)
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
+
it 'should refetch parent primary keys when retrying child import' do
|
|
116
|
+
allow(Widget).to receive(:import!).and_call_original
|
|
117
|
+
allow(Widget).to receive(:where).and_call_original
|
|
118
|
+
|
|
119
|
+
# Deadlock the first child import to trigger DeadlockRetry; let the retry pass through.
|
|
120
|
+
detail_call_count = 0
|
|
121
|
+
allow(Detail).to receive(:import!).and_wrap_original do |m, *args|
|
|
122
|
+
detail_call_count += 1
|
|
123
|
+
raise ActiveRecord::Deadlocked, 'Lock wait timeout exceeded' if detail_call_count == 1
|
|
124
|
+
|
|
125
|
+
m.call(*args)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
described_class.new(Widget, bulk_import_id_generator: bulk_id_generator).mass_update(batch)
|
|
129
|
+
|
|
130
|
+
# Parent ids written by `fill_primary_keys!` during attempt 1 stay in
|
|
131
|
+
# memory after the DB rollback, so they're stale on retry. Assert the
|
|
132
|
+
# retry re-queries. Outcome-level checks are unreliable: SQLite reuses
|
|
133
|
+
# rolled-back ids so stale memory matches coincidentally; MySQL and
|
|
134
|
+
# Postgres burn auto-increment and surface ActiveRecord::InvalidForeignKey.
|
|
135
|
+
expect(Widget).to have_received(:where).
|
|
136
|
+
with(bulk_import_id: [instance_of(String), instance_of(String)]).twice
|
|
137
|
+
expect(Widget.count).to eq(2)
|
|
138
|
+
expect(Detail.count).to eq(2)
|
|
139
|
+
expect(Widget.first.detail).not_to be_nil
|
|
140
|
+
expect(Widget.last.detail).not_to be_nil
|
|
141
|
+
end
|
|
142
|
+
|
|
115
143
|
end
|
|
116
144
|
|
|
117
145
|
context 'with save_associations_first' do
|
|
@@ -11,6 +11,11 @@ each_db_config(Deimos::KafkaTopicInfo) do
|
|
|
11
11
|
expect(described_class.last.locked_by).to eq('def')
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
it 'should raise an error if the create fails for a non-unique reason' do
|
|
15
|
+
allow(described_class).to receive(:create!).and_raise(ActiveRecord::ActiveRecordError, 'some other error')
|
|
16
|
+
expect { described_class.lock('my-topic', 'abc') }.to raise_error(ActiveRecord::ActiveRecordError)
|
|
17
|
+
end
|
|
18
|
+
|
|
14
19
|
it "should lock the topic if it's old" do
|
|
15
20
|
described_class.create!(topic: 'my-topic', locked_by: 'abc', error: true,
|
|
16
21
|
locked_at: 2.minutes.ago)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: deimos-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.5.
|
|
4
|
+
version: 2.5.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Orner
|
|
@@ -711,7 +711,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
711
711
|
- !ruby/object:Gem::Version
|
|
712
712
|
version: '0'
|
|
713
713
|
requirements: []
|
|
714
|
-
rubygems_version: 4.0.
|
|
714
|
+
rubygems_version: 4.0.6
|
|
715
715
|
specification_version: 4
|
|
716
716
|
summary: Kafka libraries for Ruby.
|
|
717
717
|
test_files: []
|