Fix race analytics: retry su unique violation in aggregazione heatmap.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
module Analytics
|
module Analytics
|
||||||
class Aggregate
|
class Aggregate
|
||||||
BATCH = 500
|
BATCH = 500
|
||||||
|
UPSERT_RETRIES = 3
|
||||||
|
|
||||||
def call
|
def call
|
||||||
loop do
|
loop do
|
||||||
@@ -45,6 +46,7 @@ module Analytics
|
|||||||
|
|
||||||
now = Time.current
|
now = Time.current
|
||||||
grouped.each do |(day, page_path, device, cell_x, cell_y), count|
|
grouped.each do |(day, page_path, device, cell_x, cell_y), count|
|
||||||
|
with_unique_retry do
|
||||||
cell = AnalyticsPageCell.find_or_initialize_by(
|
cell = AnalyticsPageCell.find_or_initialize_by(
|
||||||
day: day, page_path: page_path, device: device, cell_x: cell_x, cell_y: cell_y
|
day: day, page_path: page_path, device: device, cell_x: cell_x, cell_y: cell_y
|
||||||
)
|
)
|
||||||
@@ -54,6 +56,7 @@ module Analytics
|
|||||||
cell.save!
|
cell.save!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def apply_stats(events)
|
def apply_stats(events)
|
||||||
return if events.empty?
|
return if events.empty?
|
||||||
@@ -76,6 +79,7 @@ module Analytics
|
|||||||
|
|
||||||
now = Time.current
|
now = Time.current
|
||||||
grouped.each do |(day, page_path, device), vals|
|
grouped.each do |(day, page_path, device), vals|
|
||||||
|
with_unique_retry do
|
||||||
stat = AnalyticsPageStat.find_or_initialize_by(day: day, page_path: page_path, device: device)
|
stat = AnalyticsPageStat.find_or_initialize_by(day: day, page_path: page_path, device: device)
|
||||||
stat.pageview_count = stat.pageview_count.to_i + vals[:pageviews]
|
stat.pageview_count = stat.pageview_count.to_i + vals[:pageviews]
|
||||||
stat.scroll_samples = stat.scroll_samples.to_i + vals[:scroll_samples]
|
stat.scroll_samples = stat.scroll_samples.to_i + vals[:scroll_samples]
|
||||||
@@ -87,4 +91,17 @@ module Analytics
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def with_unique_retry
|
||||||
|
attempts = 0
|
||||||
|
begin
|
||||||
|
attempts += 1
|
||||||
|
yield
|
||||||
|
rescue ActiveRecord::RecordNotUnique
|
||||||
|
raise if attempts >= UPSERT_RETRIES
|
||||||
|
|
||||||
|
retry
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -31,7 +31,15 @@ module Analytics
|
|||||||
end
|
end
|
||||||
|
|
||||||
AnalyticsEvent.insert_all(rows) if rows.any?
|
AnalyticsEvent.insert_all(rows) if rows.any?
|
||||||
Analytics::Aggregate.new.call if rows.any?
|
if rows.any?
|
||||||
|
begin
|
||||||
|
Analytics::Aggregate.new.call
|
||||||
|
rescue ActiveRecord::RecordNotUnique => e
|
||||||
|
# Dopo i retry interni: non far fallire la richiesta analytics.
|
||||||
|
Rails.logger.warn("[analytics] aggregate race after retries, enqueue job: #{e.message}")
|
||||||
|
Analytics::AggregateJob.perform_later
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
Result.new(accepted: accepted, rejected: rejected + (@events.size - slice.size), rate_limited: false)
|
Result.new(accepted: accepted, rejected: rejected + (@events.size - slice.size), rate_limited: false)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user