Commit 27ea4c9c authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch '232831-check-redis-key-format' into 'master'

Validate Redis key format for same hash slot

Closes #232831

See merge request gitlab-org/gitlab!38782
parents fa3c9377 b6e8a0cd
......@@ -3,6 +3,9 @@
module Gitlab
module Redis
class HLL
KEY_REGEX = %r{\A(\w|-|:)*\{\w*\}(\w|-|:)*\z}.freeze
KeyFormatError = Class.new(StandardError)
def self.count(params)
self.new.count(params)
end
......@@ -11,15 +14,25 @@ module Gitlab
self.new.add(params)
end
# NOTE: It is important to make sure the keys are in the same hash slot
# https://redis.io/topics/cluster-spec#keys-hash-tags
def count(keys:)
Gitlab::Redis::SharedState.with do |redis|
redis.pfcount(*keys)
end
end
# Check a basic format for the Redis key in order to ensure the keys are in the same hash slot
#
# Examples of keys
# project:{1}:set_a
# project:{1}:set_b
# project:{2}:set_c
# 2020-216-{project_action}
# i_{analytics}_dev_ops_score-2020-32
def add(key:, value:, expiry:)
unless KEY_REGEX.match?(key)
raise KeyFormatError.new("Invalid key format. #{key} key should have changeable parts in curly braces. See https://docs.gitlab.com/ee/development/redis.html#multi-key-commands")
end
Gitlab::Redis::SharedState.with do |redis|
redis.multi do |multi|
multi.pfadd(key, value)
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Redis::HLL, :clean_gitlab_redis_shared_state do
describe '.add' do
it 'raise an error when using an invalid key format' do
expect { described_class.add(key: 'test', value: 1, expiry: 1.day) }.to raise_error(Gitlab::Redis::HLL::KeyFormatError)
expect { described_class.add(key: 'test-{metric', value: 1, expiry: 1.day) }.to raise_error(Gitlab::Redis::HLL::KeyFormatError)
expect { described_class.add(key: 'test-{metric}}', value: 1, expiry: 1.day) }.to raise_error(Gitlab::Redis::HLL::KeyFormatError)
end
it "doesn't raise error when having correct format" do
expect { described_class.add(key: 'test-{metric}', value: 1, expiry: 1.day) }.not_to raise_error
expect { described_class.add(key: 'test-{metric}-1', value: 1, expiry: 1.day) }.not_to raise_error
expect { described_class.add(key: 'test:{metric}-1', value: 1, expiry: 1.day) }.not_to raise_error
expect { described_class.add(key: '2020-216-{project_action}', value: 1, expiry: 1.day) }.not_to raise_error
expect { described_class.add(key: 'i_{analytics}_dev_ops_score-2020-32', value: 1, expiry: 1.day) }.not_to raise_error
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