PERF: perform all cached counting in background (#15991)

Previously cached counting made redis calls in main thread and performed
the flush in main thread.

This could lead to pathological states in extreme heavy load.

This refactor reduces load and cleans up the interface
This commit is contained in:
Sam
2022-02-23 03:45:25 +11:00
committed by GitHub
parent 98a7fa3d1a
commit d4d3580761
9 changed files with 367 additions and 370 deletions

View File

@ -23,50 +23,16 @@ class ApplicationRequest < ActiveRecord::Base
@disabled = false
end
def self.increment!(type, opts = nil)
def self.increment!(req_type)
return if @disabled
perform_increment!(redis_key(type), opts)
perform_increment!(req_type)
end
def self.write_cache!(date = nil)
if date.nil?
write_cache!(Time.now.utc)
write_cache!(Time.now.utc.yesterday)
return
end
self.last_flush = Time.now.utc
date = date.to_date
req_types.each do |req_type, _|
val = get_and_reset(redis_key(req_type, date))
next if val == 0
id = req_id(date, req_type)
where(id: id).update_all(["count = count + ?", val])
end
rescue Redis::CommandError => e
raise unless e.message =~ /READONLY/
nil
def self.write_cache!(req_type, count, date)
id = req_id(date, req_type)
where(id: id).update_all(["count = count + ?", count])
end
def self.clear_cache!(date = nil)
if date.nil?
clear_cache!(Time.now.utc)
clear_cache!(Time.now.utc.yesterday)
return
end
req_types.each do |req_type, _|
key = redis_key(req_type, date)
Discourse.redis.del key
end
end
protected
def self.req_id(date, req_type, retries = 0)
req_type_id = req_types[req_type]
@ -83,10 +49,6 @@ class ApplicationRequest < ActiveRecord::Base
end
end
def self.redis_key(req_type, time = Time.now.utc)
"app_req_#{req_type}#{time.strftime('%Y%m%d')}"
end
def self.stats
s = HashWithIndifferentAccess.new({})