Commit c4e11db3 authored by Quang-Minh Nguyen's avatar Quang-Minh Nguyen

Implement a subscriber for per-request cache usage of RackAttack

Issue https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/751
parent 7d3f762c
# frozen_string_literal: true
module Gitlab
module Metrics
module Subscribers
# Instrument the cache operations of RackAttack to use in structured
# logs. Two fields are exposed:
# - rack_attack_redis_count: the number of redis calls triggered by
# RackAttack in a request.
# - rack_attack_redis_duration_s: the total duration of all redis calls
# triggered by RackAttack in a request.
class RackAttack < ActiveSupport::Subscriber
INSTRUMENTATION_STORE_KEY = :rack_attack_instrumentation
attach_to 'redis'
PAYLOAD_KEYS = [
:rack_attack_redis_count,
:rack_attack_redis_duration_s
].freeze
def self.payload
Gitlab::SafeRequestStore[INSTRUMENTATION_STORE_KEY] ||= {
rack_attack_redis_count: 0,
rack_attack_redis_duration_s: 0.0
}
end
def rack_attack(event)
self.class.payload[:rack_attack_redis_count] += 1
self.class.payload[:rack_attack_redis_duration_s] += event.duration.to_f / 1000
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Metrics::Subscribers::RackAttack, :request_store do
let(:subscriber) { described_class.new }
describe '.payload' do
context 'when the request store is empty' do
it 'returns empty data' do
expect(described_class.payload).to eql(
rack_attack_redis_count: 0,
rack_attack_redis_duration_s: 0.0
)
end
end
context 'when the request store already has data' do
before do
Gitlab::SafeRequestStore[:rack_attack_instrumentation] = {
rack_attack_redis_count: 10,
rack_attack_redis_duration_s: 9.0
}
end
it 'returns the accumulated data' do
expect(described_class.payload).to eql(
rack_attack_redis_count: 10,
rack_attack_redis_duration_s: 9.0
)
end
end
end
describe '#rack_attack' do
it 'accumulates per-request RackAttack cache usage' do
freeze_time do
subscriber.rack_attack(
ActiveSupport::Notifications::Event.new(
'rack_attack.redis', Time.current, Time.current + 1.second, '1', { operation: 'fetch' }
)
)
subscriber.rack_attack(
ActiveSupport::Notifications::Event.new(
'rack_attack.redis', Time.current, Time.current + 2.seconds, '1', { operation: 'write' }
)
)
subscriber.rack_attack(
ActiveSupport::Notifications::Event.new(
'rack_attack.redis', Time.current, Time.current + 3.seconds, '1', { operation: 'read' }
)
)
end
expect(Gitlab::SafeRequestStore[:rack_attack_instrumentation]).to eql(
rack_attack_redis_count: 3,
rack_attack_redis_duration_s: 6.0
)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment