93 lines
2.6 KiB
Ruby
93 lines
2.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# HubLoad - Calculates dynamic event sampling rate based on system load
|
|
#
|
|
# This service monitors SolidQueue depth and adjusts sampling rates to prevent
|
|
# the Hub from being overwhelmed while ensuring critical events are always captured.
|
|
class HubLoad
|
|
# Queue depth thresholds
|
|
THRESHOLDS = {
|
|
normal: 0..1_000, # 100% sampling
|
|
moderate: 1_001..5_000, # 50% sampling
|
|
high: 5_001..10_000, # 20% sampling
|
|
critical: 10_001..Float::INFINITY # 5% sampling
|
|
}.freeze
|
|
|
|
SAMPLING_RATES = {
|
|
normal: { allowed: 1.0, blocked: 1.0, rate_limited: 1.0 },
|
|
moderate: { allowed: 0.5, blocked: 1.0, rate_limited: 1.0 },
|
|
high: { allowed: 0.2, blocked: 1.0, rate_limited: 1.0 },
|
|
critical: { allowed: 0.05, blocked: 1.0, rate_limited: 1.0 }
|
|
}.freeze
|
|
|
|
# Get current sampling configuration based on load
|
|
def self.current_sampling
|
|
load_level = calculate_load_level
|
|
rates = SAMPLING_RATES[load_level]
|
|
|
|
{
|
|
allowed_requests: rates[:allowed],
|
|
blocked_requests: rates[:blocked],
|
|
rate_limited_requests: rates[:rate_limited],
|
|
effective_until: next_sync_time,
|
|
load_level: load_level,
|
|
queue_depth: queue_depth
|
|
}
|
|
end
|
|
|
|
# Test method for different load levels
|
|
def self.test_sampling(load_level)
|
|
rates = SAMPLING_RATES[load_level] || SAMPLING_RATES[:normal]
|
|
|
|
{
|
|
allowed_requests: rates[:allowed],
|
|
blocked_requests: rates[:blocked],
|
|
rate_limited_requests: rates[:rate_limited],
|
|
effective_until: next_sync_time,
|
|
load_level: load_level,
|
|
queue_depth: THRESHOLDS[load_level].first + 100
|
|
}
|
|
end
|
|
|
|
# Calculate when sampling should be rechecked (next agent sync)
|
|
def self.next_sync_time
|
|
10.seconds.from_now.iso8601(3)
|
|
end
|
|
|
|
# Get current queue depth
|
|
def self.queue_depth
|
|
# SolidQueue stores jobs in the jobs table
|
|
# Count pending/running jobs only
|
|
SolidQueue::Job.where(finished_at: nil).count
|
|
rescue StandardError => e
|
|
Rails.logger.error "Failed to get queue depth: #{e.message}"
|
|
0
|
|
end
|
|
|
|
# Determine load level based on queue depth
|
|
def self.calculate_load_level
|
|
depth = queue_depth
|
|
|
|
THRESHOLDS.each do |level, range|
|
|
return level if range.cover?(depth)
|
|
end
|
|
|
|
:critical # Fallback
|
|
end
|
|
|
|
# Check if hub is under heavy load
|
|
def self.overloaded?
|
|
calculate_load_level.in?([:high, :critical])
|
|
end
|
|
|
|
# Get load statistics for monitoring
|
|
def self.stats
|
|
{
|
|
queue_depth: queue_depth,
|
|
load_level: calculate_load_level,
|
|
sampling_rates: SAMPLING_RATES[calculate_load_level],
|
|
overloaded: overloaded?
|
|
}
|
|
end
|
|
end
|