dionysus-rb 1.7.0 → 1.7.1
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 +3 -0
- data/Gemfile.lock +1 -1
- data/lib/dionysus/producer/embedded_timestamp_repair.rb +23 -7
- data/lib/dionysus/version.rb +1 -1
- 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: 4b87f084174020b048f571661e800ea514567cce186ed7701c8db43ada5f35be
|
|
4
|
+
data.tar.gz: 62f4126b20a85405bb3337eb9b0bd71d540e39943d2a2e1b5a87b86c1eabbe5a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0bb5902c1a0a9aaeec93ffbd16b0408fbe0288252ef36e31cca95a67ee2eb15bdb41cf120af4f6a6aec60735a2c2d9f6b571d4aad3a506ef2e214f7731cc7d7
|
|
7
|
+
data.tar.gz: ef7a256c9ca43d3987055df6c49abfe5fcdbf53bd855b7af00ba39f0f4a394dd3923559d69d1b8abc4e8639bc0f7a6c0398b55c2b86c40188a9ee5512ee053e3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.7.1]
|
|
4
|
+
- Parse an ISO8601 string timestamp in the payload instead of ignoring it. 1.7.0 required every timestamp to answer `acts_like_time?`, so a serializer that renders the parent's `updated_at` as a string made the whole class a silent no-op: the parent never looked time-like, no payload was ever examined, no row was ever corrected and `dionysus.publish.timestamp_repair` never fired.
|
|
5
|
+
|
|
3
6
|
## [1.7.0]
|
|
4
7
|
- Correct a row whose own `updated_at` predates a record embedded in its payload, then serialize again, behind `config.touch_records_behind_their_embedded_records` (default `false`). A serializer reads the parent's columns before the associations, so a child committed in between arrives under a timestamp older than itself, and the consumer discards the payload together with that child.
|
|
5
8
|
|
data/Gemfile.lock
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
class Dionysus::Producer::EmbeddedTimestampRepair
|
|
4
4
|
TIMESTAMP_ATTRIBUTE = "updated_at"
|
|
5
5
|
PRIMARY_KEY_ATTRIBUTE = "id"
|
|
6
|
+
ISO8601_WITH_OFFSET = %r{\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})\z}
|
|
6
7
|
|
|
7
8
|
# Takes the block that serializes, so a repaired record can be serialized again in one place.
|
|
8
9
|
def self.call(records, config, &)
|
|
@@ -43,8 +44,9 @@ class Dionysus::Producer::EmbeddedTimestampRepair
|
|
|
43
44
|
def repaired?(record, record_payload)
|
|
44
45
|
return false unless repairable?(record, record_payload)
|
|
45
46
|
|
|
47
|
+
published_at = coerce_time(record_payload[TIMESTAMP_ATTRIBUTE])
|
|
46
48
|
latest = embedded_timestamps(record_payload).max
|
|
47
|
-
return false unless latest && latest >
|
|
49
|
+
return false unless published_at && latest && latest > published_at
|
|
48
50
|
|
|
49
51
|
# WHERE guards the write: a stale read must never move the row backwards. When the row is already
|
|
50
52
|
# ahead nothing is written, and the reload alone repairs the payload.
|
|
@@ -61,8 +63,7 @@ class Dionysus::Producer::EmbeddedTimestampRepair
|
|
|
61
63
|
|
|
62
64
|
def repairable?(record, record_payload)
|
|
63
65
|
record.is_a?(ActiveRecord::Base) && record.persisted? &&
|
|
64
|
-
record_payload.is_a?(Hash) && record_payload[PRIMARY_KEY_ATTRIBUTE] == record.id
|
|
65
|
-
time_like?(record_payload[TIMESTAMP_ATTRIBUTE])
|
|
66
|
+
record_payload.is_a?(Hash) && record_payload[PRIMARY_KEY_ATTRIBUTE] == record.id
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
def embedded_timestamps(record_payload)
|
|
@@ -70,8 +71,7 @@ class Dionysus::Producer::EmbeddedTimestampRepair
|
|
|
70
71
|
Array.wrap(value).filter_map do |embedded|
|
|
71
72
|
next unless embedded.is_a?(Hash)
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
timestamp if time_like?(timestamp)
|
|
74
|
+
coerce_time(embedded[TIMESTAMP_ATTRIBUTE])
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
end
|
|
@@ -81,7 +81,23 @@ class Dionysus::Producer::EmbeddedTimestampRepair
|
|
|
81
81
|
tags: ["model:#{record.class}", "outcome:#{updated.zero? ? "stale_read" : "row_behind"}"])
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
# A serializer may render the timestamp it is about to publish, so one payload carries both shapes.
|
|
85
|
+
def coerce_time(value)
|
|
86
|
+
case value
|
|
87
|
+
when ActiveSupport::TimeWithZone, Time then value
|
|
88
|
+
when String then parse_iso8601(value)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def parse_iso8601(value)
|
|
93
|
+
return nil unless ISO8601_WITH_OFFSET.match?(value)
|
|
94
|
+
|
|
95
|
+
time = Time.iso8601(value)
|
|
96
|
+
# Time.iso8601 normalizes an impossible date: 2026-09-31 becomes October 1.
|
|
97
|
+
return nil unless value.start_with?(time.strftime("%Y-%m-%d"))
|
|
98
|
+
|
|
99
|
+
time.in_time_zone
|
|
100
|
+
rescue ArgumentError
|
|
101
|
+
nil
|
|
86
102
|
end
|
|
87
103
|
end
|
data/lib/dionysus/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dionysus-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.7.
|
|
4
|
+
version: 1.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Karol Galanciak
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|