journaled 6.2.4 → 6.2.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fee2c705ef818a62962f72a9dba7cb73b7aaf861578ba7d1549dd9c43f1d34e9
4
- data.tar.gz: 896fb56884b97a70e088bdcaed8ea3407798663a62d4dcca7d079935c3616212
3
+ metadata.gz: ccf34c7b5e32419b7b42919fc2325a8132655ade454e437523f55588b92ea901
4
+ data.tar.gz: 788f394e0c7ecdab76e5cb862d21add0d4a96d3ac2d766eead458159f511d842
5
5
  SHA512:
6
- metadata.gz: 2ae1d7528fadaafea0ce68d774a151d1f715899c213ceb1f9b8c7cdbfba88755a65e758e643a674fe11a01ef3e95b6ed0d0d7c3b09363831cec6719c553fd49a
7
- data.tar.gz: d6417dbd10fc40995feb9478da0eb6f2c4659bc283e70ce037fdca5953c4abc24ea5ad7e66f8883e0ba464d569a932493fa94816491d8ec530484589d7b7b55a
6
+ metadata.gz: fc9c29ef11509f18647b4c90f3890f0da76318d5163ac378f561d08e38a61dec729dfdb768c2c1c2d7846d7d53b32ff4d06ae2389ceef41b19f5fc111d3d6bcf
7
+ data.tar.gz: f91ef462e9d89d492f083a546b6106c328baf3ade91e7ac88a9f9b13d3b203a7a0c4c03968ac372b007f3cb2ec7881f1497f78d5485c3b67a777ce7258f7f5cc
@@ -19,6 +19,7 @@ module Journaled
19
19
  attribute :event_data, :json
20
20
 
21
21
  validates :event_type, :event_data, :partition_key, :stream_name, presence: true
22
+ validate :failed_at_and_failure_reason_must_be_consistent
22
23
 
23
24
  scope :ready_to_process, -> {
24
25
  where(failed_at: nil)
@@ -63,6 +64,14 @@ module Journaled
63
64
  def self.oldest_non_failed_timestamp
64
65
  ready_to_process.order(:id).limit(1).pick(:created_at)
65
66
  end
67
+
68
+ private
69
+
70
+ def failed_at_and_failure_reason_must_be_consistent
71
+ if failed_at.present? != failure_reason.present?
72
+ errors.add(:base, 'failed_at and failure_reason must both be present or both be absent')
73
+ end
74
+ end
66
75
  end
67
76
  end
68
77
  end
@@ -15,6 +15,8 @@ module Journaled
15
15
  'ValidationException',
16
16
  ].freeze
17
17
 
18
+ BATCH_TOO_LARGE_PATTERN = /too large/i
19
+
18
20
  # Send a batch of database events to Kinesis
19
21
  #
20
22
  # Uses put_records batch API. Groups events by stream and sends each group as a batch.
@@ -40,11 +42,10 @@ module Journaled
40
42
  begin
41
43
  response = kinesis_client.put_records(stream_name:, records:)
42
44
  process_response(response, stream_events)
43
- rescue Aws::Kinesis::Errors::ValidationException
44
- # Re-raise batch-level validation errors (configuration issues)
45
- # These indicate invalid stream name, batch too large, etc.
46
- # Not event data problems - requires manual intervention
47
- raise
45
+ rescue Aws::Kinesis::Errors::ValidationException => e
46
+ raise unless e.message.match?(BATCH_TOO_LARGE_PATTERN)
47
+
48
+ handle_batch_too_large(stream_name, stream_events)
48
49
  rescue StandardError => e
49
50
  # Handle transient errors (throttling, network issues, service unavailable)
50
51
  handle_transient_batch_error(e, stream_events)
@@ -93,6 +94,36 @@ module Journaled
93
94
  )
94
95
  end
95
96
 
97
+ def handle_batch_too_large(stream_name, stream_events)
98
+ if stream_events.size <= 1
99
+ # Single event exceeds payload limit — treat as permanent failure
100
+ return {
101
+ succeeded: [],
102
+ failed: stream_events.map do |event|
103
+ create_failed_event(
104
+ event,
105
+ error_code: 'ValidationException',
106
+ error_message: 'Record exceeds Kinesis payload limit',
107
+ transient: false,
108
+ )
109
+ end,
110
+ }
111
+ end
112
+
113
+ Rails.logger.warn(
114
+ "[journaled] Batch too large for Kinesis (#{stream_events.size} events), splitting in half and retrying",
115
+ )
116
+
117
+ mid = stream_events.size / 2
118
+ first_half = send_stream_batch(stream_name, stream_events[...mid])
119
+ second_half = send_stream_batch(stream_name, stream_events[mid...])
120
+
121
+ {
122
+ succeeded: first_half[:succeeded] + second_half[:succeeded],
123
+ failed: first_half[:failed] + second_half[:failed],
124
+ }
125
+ end
126
+
96
127
  def handle_transient_batch_error(error, stream_events)
97
128
  Rails.logger.error("Kinesis batch send failed (transient): #{error.class} - #{error.message}")
98
129
 
@@ -73,7 +73,7 @@ module Journaled
73
73
  Event.select(
74
74
  'COUNT(*) AS total_count',
75
75
  'COUNT(*) FILTER (WHERE failed_at IS NULL) AS workable_count',
76
- 'COUNT(*) FILTER (WHERE failure_reason IS NOT NULL AND failed_at IS NULL) AS failed_count',
76
+ 'COUNT(*) FILTER (WHERE failed_at IS NOT NULL) AS failed_count',
77
77
  'MIN(created_at) FILTER (WHERE failed_at IS NULL) AS oldest_non_failed_timestamp',
78
78
  ).to_sql,
79
79
  )
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Journaled
4
- VERSION = "6.2.4"
4
+ VERSION = "6.2.5"
5
5
  end
metadata CHANGED
@@ -1,16 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: journaled
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.2.4
4
+ version: 6.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jake Lipson
8
8
  - Corey Alexander
9
9
  - Cyrus Eslami
10
10
  - John Mileham
11
+ autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 1980-01-02 00:00:00.000000000 Z
14
+ date: 2026-03-03 00:00:00.000000000 Z
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
17
  name: activejob
@@ -324,7 +325,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
324
325
  - !ruby/object:Gem::Version
325
326
  version: '0'
326
327
  requirements: []
327
- rubygems_version: 3.6.8
328
+ rubygems_version: 3.4.10
329
+ signing_key:
328
330
  specification_version: 4
329
331
  summary: Journaling for Betterment apps.
330
332
  test_files: []