Class: PumaMetricsEngine::QueueTimeTracker

Inherits:
Object
  • Object
show all
Defined in:
lib/puma_metrics_engine/queue_time_tracker.rb

Constant Summary collapse

TTL_SECONDS =

5 minutes

300
REQUESTS_KEY =
"puma:request_timestamps"
QUEUE_TIMES_KEY =
"puma:queue_times"

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ QueueTimeTracker

Returns a new instance of QueueTimeTracker.



9
10
11
# File 'lib/puma_metrics_engine/queue_time_tracker.rb', line 9

def initialize(app)
  @app = app
end

Instance Method Details

#call(env) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/puma_metrics_engine/queue_time_tracker.rb', line 13

def call(env)
  request_start_time = extract_request_start_time(env)
  process_start_time = Time.now.to_f

  # Log header presence for debugging
  if defined?(Rails)
    header_value = env["HTTP_X_REQUEST_START"] || env["X-Request-Start"]
    Rails.logger.debug("[QueueTimeTracker] X-Request-Start header: #{header_value.inspect}") if header_value
    Rails.logger.debug("[QueueTimeTracker] No X-Request-Start header found") unless header_value
  end

  status, headers, response = @app.call(env)

  # Calculate queue time if we have request start time
  begin
    if request_start_time
      queue_time_ms = ((process_start_time - request_start_time) * 1000).round(2)
      
      # Only store if queue time is reasonable (positive and less than 1 hour)
      # Negative values indicate clock skew, very large values are likely errors
      if queue_time_ms >= 0 && queue_time_ms < 3_600_000
        timestamp = process_start_time
        # Store in Redis asynchronously to avoid blocking the request
        store_metrics_async(timestamp, queue_time_ms)
        Rails.logger.debug("[QueueTimeTracker] Stored queue time: #{queue_time_ms}ms") if defined?(Rails)
      else
        # Still track request timestamp even if queue time is invalid
        Rails.logger.warn("[QueueTimeTracker] Invalid queue time: #{queue_time_ms}ms (rejected)") if defined?(Rails)
        store_request_timestamp_async(process_start_time)
      end
    else
      # Still track request timestamp even without queue time
      store_request_timestamp_async(process_start_time)
    end
  rescue StandardError => e
    # Don't let tracking errors break the request
    Rails.logger.error("[QueueTimeTracker] Error: #{e.message}") if defined?(Rails)
    Rails.logger.error("[QueueTimeTracker] Backtrace: #{e.backtrace.first(5).join("\n")}") if defined?(Rails)
  end

  [status, headers, response]
end