Add rps tracker to footer (#364)

This commit is contained in:
Max Wofford
2025-06-25 20:20:07 -04:00
committed by GitHub
parent 4fe0275e36
commit 2212349454
4 changed files with 68 additions and 0 deletions

View File

@@ -3,6 +3,7 @@ class ApplicationController < ActionController::Base
before_action :honeybadger_context, if: :current_user
before_action :initialize_cache_counters
before_action :try_rack_mini_profiler_enable
before_action :track_request
after_action :track_action
around_action :switch_time_zone, if: :current_user
@@ -30,6 +31,10 @@ class ApplicationController < ActionController::Base
ahoy.track "Ran action", request.path_parameters
end
def track_request
RequestCounter.increment
end
def try_rack_mini_profiler_enable
if current_user && current_user.is_admin?
Rack::MiniProfiler.authorize_request

View File

@@ -5,6 +5,11 @@ module ApplicationHelper
{ hits: hits, misses: misses }
end
def requests_per_second
rps = RequestCounter.per_second
rps == :high_load ? "lots of req/sec" : "#{rps} req/sec"
end
def admin_tool(class_name = "", element = "div", **options, &block)
return unless current_user&.is_admin?
concat content_tag(element, class: "admin-tool #{class_name}", **options, &block)

View File

@@ -0,0 +1,57 @@
class RequestCounter
WINDOW_SIZE = 10 # seconds - shorter window for more responsive rates
HIGH_LOAD_THRESHOLD = 500 # req/sec to disable tracking
CIRCUIT_BREAKER_DURATION = 30 # seconds to stay disabled
@buckets = {}
@disabled_until = nil
class << self
def increment
return if disabled?
current_time = Time.current.to_i
@buckets[current_time] = (@buckets[current_time] || 0) + 1
# Check if we should disable due to high load
check_circuit_breaker(current_time)
# Periodically clean old buckets (1% chance)
cleanup if rand(100) == 0
end
def per_second
return :high_load if disabled?
current_time = Time.current.to_i
cutoff = current_time - WINDOW_SIZE
total = @buckets.select { |timestamp, _| timestamp >= cutoff }.values.sum
(total.to_f / WINDOW_SIZE).round(2)
end
private
def disabled?
@disabled_until && Time.current.to_i < @disabled_until
end
def check_circuit_breaker(current_time)
# Check last 5 seconds for high load
recent_total = @buckets.select { |ts, _| ts >= current_time - 5 }.values.sum
if recent_total > HIGH_LOAD_THRESHOLD * 5 # 5 seconds worth
@disabled_until = current_time + CIRCUIT_BREAKER_DURATION
@buckets.clear # Clear to reduce memory
end
end
def cleanup
return if disabled? # Skip cleanup when disabled
current_time = Time.current.to_i
cutoff = current_time - WINDOW_SIZE - 10 # extra buffer
@buckets.reject! { |timestamp, _| timestamp < cutoff }
end
end
end

View File

@@ -168,6 +168,7 @@
in the last 24 hours.
(DB: <%= pluralize(QueryCount::Counter.counter, "query") %>, <%= QueryCount::Counter.counter_cache %> cached)
(CACHE: <%= cache_stats[:hits] %> hits, <%= cache_stats[:misses] %> misses)
(<%= requests_per_second %>)
</p>
<% if session[:impersonater_user_id] %>
<%= link_to "Stop impersonating", stop_impersonating_path, class: "impersonate-link", data: { turbo_prefetch: "false" } %>