Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
c66fb99d
Commit
c66fb99d
authored
Jan 11, 2022
by
nmilojevic1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove redis MultiStore implementation
Changelog: removed
parent
f3a1cbfc
Changes
7
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
12 additions
and
1104 deletions
+12
-1104
config/feature_flags/development/use_primary_and_secondary_stores_for_sessions.yml
...lopment/use_primary_and_secondary_stores_for_sessions.yml
+0
-8
config/feature_flags/development/use_primary_store_as_default_for_sessions.yml
...development/use_primary_store_as_default_for_sessions.yml
+0
-8
lib/gitlab/redis/multi_store.rb
lib/gitlab/redis/multi_store.rb
+0
-232
lib/gitlab/redis/sessions.rb
lib/gitlab/redis/sessions.rb
+3
-33
spec/lib/gitlab/redis/multi_store_spec.rb
spec/lib/gitlab/redis/multi_store_spec.rb
+0
-716
spec/lib/gitlab/redis/sessions_spec.rb
spec/lib/gitlab/redis/sessions_spec.rb
+9
-64
spec/support/shared_examples/lib/gitlab/redis/multi_store_feature_flags_shared_examples.rb
...gitlab/redis/multi_store_feature_flags_shared_examples.rb
+0
-43
No files found.
config/feature_flags/development/use_primary_and_secondary_stores_for_sessions.yml
deleted
100644 → 0
View file @
f3a1cbfc
---
name
:
use_primary_and_secondary_stores_for_sessions
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73660
rollout_issue_url
:
https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1429
milestone
:
'
14.6'
type
:
development
group
:
group::memory
default_enabled
:
false
config/feature_flags/development/use_primary_store_as_default_for_sessions.yml
deleted
100644 → 0
View file @
f3a1cbfc
---
name
:
use_primary_store_as_default_for_sessions
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75258
rollout_issue_url
:
milestone
:
'
14.6'
type
:
development
group
:
group::memory
default_enabled
:
false
lib/gitlab/redis/multi_store.rb
deleted
100644 → 0
View file @
f3a1cbfc
# frozen_string_literal: true
module
Gitlab
module
Redis
class
MultiStore
include
Gitlab
::
Utils
::
StrongMemoize
class
ReadFromPrimaryError
<
StandardError
def
message
'Value not found on the redis primary store. Read from the redis secondary store successful.'
end
end
class
MethodMissingError
<
StandardError
def
message
'Method missing. Falling back to execute method on the redis secondary store.'
end
end
attr_reader
:primary_store
,
:secondary_store
,
:instance_name
FAILED_TO_READ_ERROR_MESSAGE
=
'Failed to read from the redis primary_store.'
FAILED_TO_WRITE_ERROR_MESSAGE
=
'Failed to write to the redis primary_store.'
SKIP_LOG_METHOD_MISSING_FOR_COMMANDS
=
%i(info)
.
freeze
READ_COMMANDS
=
%i(
get
mget
smembers
scard
)
.
freeze
WRITE_COMMANDS
=
%i(
set
setnx
setex
sadd
srem
del
pipelined
flushdb
)
.
freeze
def
initialize
(
primary_store
,
secondary_store
,
instance_name
)
@primary_store
=
primary_store
@secondary_store
=
secondary_store
@instance_name
=
instance_name
validate_stores!
end
# rubocop:disable GitlabSecurity/PublicSend
READ_COMMANDS
.
each
do
|
name
|
define_method
(
name
)
do
|*
args
,
&
block
|
if
use_primary_and_secondary_stores?
read_command
(
name
,
*
args
,
&
block
)
else
default_store
.
send
(
name
,
*
args
,
&
block
)
end
end
end
WRITE_COMMANDS
.
each
do
|
name
|
define_method
(
name
)
do
|*
args
,
&
block
|
if
use_primary_and_secondary_stores?
write_command
(
name
,
*
args
,
&
block
)
else
default_store
.
send
(
name
,
*
args
,
&
block
)
end
end
end
def
method_missing
(
...
)
return
@instance
.
send
(
...
)
if
@instance
log_method_missing
(
...
)
default_store
.
send
(
...
)
end
# rubocop:enable GitlabSecurity/PublicSend
def
respond_to_missing?
(
command_name
,
include_private
=
false
)
true
end
# This is needed because of Redis::Rack::Connection is requiring Redis::Store
# https://github.com/redis-store/redis-rack/blob/a833086ba494083b6a384a1a4e58b36573a9165d/lib/redis/rack/connection.rb#L15
# Done similarly in https://github.com/lsegal/yard/blob/main/lib/yard/templates/template.rb#L122
def
is_a?
(
klass
)
return
true
if
klass
==
default_store
.
class
super
(
klass
)
end
alias_method
:kind_of?
,
:is_a?
def
to_s
use_primary_and_secondary_stores?
?
primary_store
.
to_s
:
default_store
.
to_s
end
def
use_primary_and_secondary_stores?
feature_table_exists?
&&
Feature
.
enabled?
(
"use_primary_and_secondary_stores_for_
#{
instance_name
.
underscore
}
"
,
default_enabled: :yaml
)
&&
!
same_redis_store?
end
def
use_primary_store_as_default?
feature_table_exists?
&&
Feature
.
enabled?
(
"use_primary_store_as_default_for_
#{
instance_name
.
underscore
}
"
,
default_enabled: :yaml
)
&&
!
same_redis_store?
end
private
# @return [Boolean]
def
feature_table_exists?
Feature
::
FlipperFeature
.
table_exists?
rescue
StandardError
false
end
def
default_store
use_primary_store_as_default?
?
primary_store
:
secondary_store
end
def
log_method_missing
(
command_name
,
*
_args
)
return
if
SKIP_LOG_METHOD_MISSING_FOR_COMMANDS
.
include?
(
command_name
)
log_error
(
MethodMissingError
.
new
,
command_name
)
increment_method_missing_count
(
command_name
)
end
def
read_command
(
command_name
,
*
args
,
&
block
)
if
@instance
send_command
(
@instance
,
command_name
,
*
args
,
&
block
)
else
read_one_with_fallback
(
command_name
,
*
args
,
&
block
)
end
end
def
write_command
(
command_name
,
*
args
,
&
block
)
if
@instance
send_command
(
@instance
,
command_name
,
*
args
,
&
block
)
else
write_both
(
command_name
,
*
args
,
&
block
)
end
end
def
read_one_with_fallback
(
command_name
,
*
args
,
&
block
)
begin
value
=
send_command
(
primary_store
,
command_name
,
*
args
,
&
block
)
rescue
StandardError
=>
e
log_error
(
e
,
command_name
,
multi_store_error_message:
FAILED_TO_READ_ERROR_MESSAGE
)
end
value
||=
fallback_read
(
command_name
,
*
args
,
&
block
)
value
end
def
fallback_read
(
command_name
,
*
args
,
&
block
)
value
=
send_command
(
secondary_store
,
command_name
,
*
args
,
&
block
)
if
value
log_error
(
ReadFromPrimaryError
.
new
,
command_name
)
increment_read_fallback_count
(
command_name
)
end
value
end
def
write_both
(
command_name
,
*
args
,
&
block
)
begin
send_command
(
primary_store
,
command_name
,
*
args
,
&
block
)
rescue
StandardError
=>
e
log_error
(
e
,
command_name
,
multi_store_error_message:
FAILED_TO_WRITE_ERROR_MESSAGE
)
end
send_command
(
secondary_store
,
command_name
,
*
args
,
&
block
)
end
def
same_redis_store?
strong_memoize
(
:same_redis_store
)
do
# <Redis client v4.4.0 for redis:///path_to/redis/redis.socket/5>"
primary_store
.
inspect
==
secondary_store
.
inspect
end
end
# rubocop:disable GitlabSecurity/PublicSend
def
send_command
(
redis_instance
,
command_name
,
*
args
,
&
block
)
if
block_given?
# Make sure that block is wrapped and executed only on the redis instance that is executing the block
redis_instance
.
send
(
command_name
,
*
args
)
do
|*
params
|
with_instance
(
redis_instance
,
*
params
,
&
block
)
end
else
redis_instance
.
send
(
command_name
,
*
args
)
end
end
# rubocop:enable GitlabSecurity/PublicSend
def
with_instance
(
instance
,
*
params
)
@instance
=
instance
yield
(
*
params
)
ensure
@instance
=
nil
end
def
increment_read_fallback_count
(
command_name
)
@read_fallback_counter
||=
Gitlab
::
Metrics
.
counter
(
:gitlab_redis_multi_store_read_fallback_total
,
'Client side Redis MultiStore reading fallback'
)
@read_fallback_counter
.
increment
(
command:
command_name
,
instance_name:
instance_name
)
end
def
increment_method_missing_count
(
command_name
)
@method_missing_counter
||=
Gitlab
::
Metrics
.
counter
(
:gitlab_redis_multi_store_method_missing_total
,
'Client side Redis MultiStore method missing'
)
@method_missing_counter
.
increment
(
command:
command_name
,
instance_name:
instance_name
)
end
def
validate_stores!
raise
ArgumentError
,
'primary_store is required'
unless
primary_store
raise
ArgumentError
,
'secondary_store is required'
unless
secondary_store
raise
ArgumentError
,
'instance_name is required'
unless
instance_name
raise
ArgumentError
,
'invalid primary_store'
unless
primary_store
.
is_a?
(
::
Redis
)
raise
ArgumentError
,
'invalid secondary_store'
unless
secondary_store
.
is_a?
(
::
Redis
)
end
def
log_error
(
exception
,
command_name
,
extra
=
{})
Gitlab
::
ErrorTracking
.
log_exception
(
exception
,
command_name:
command_name
,
extra:
extra
.
merge
(
instance_name:
instance_name
))
end
end
end
end
lib/gitlab/redis/sessions.rb
View file @
c66fb99d
...
@@ -9,40 +9,10 @@ module Gitlab
...
@@ -9,40 +9,10 @@ module Gitlab
IP_SESSIONS_LOOKUP_NAMESPACE
=
'session:lookup:ip:gitlab2'
IP_SESSIONS_LOOKUP_NAMESPACE
=
'session:lookup:ip:gitlab2'
OTP_SESSIONS_NAMESPACE
=
'session:otp'
OTP_SESSIONS_NAMESPACE
=
'session:otp'
class
<<
self
# The data we store on Sessions used to be stored on SharedState.
# The data we store on Sessions used to be stored on SharedState.
def
config_fallback
def
self
.
config_fallback
SharedState
SharedState
end
end
private
def
redis
# Don't use multistore if redis.sessions configuration is not provided
return
super
if
config_fallback?
primary_store
=
::
Redis
.
new
(
params
)
secondary_store
=
::
Redis
.
new
(
config_fallback
.
params
)
MultiStore
.
new
(
primary_store
,
secondary_store
,
store_name
)
end
end
def
store
(
extras
=
{})
# Don't use multistore if redis.sessions configuration is not provided
return
super
if
self
.
class
.
config_fallback?
primary_store
=
create_redis_store
(
redis_store_options
,
extras
)
secondary_store
=
create_redis_store
(
self
.
class
.
config_fallback
.
params
,
extras
)
MultiStore
.
new
(
primary_store
,
secondary_store
,
self
.
class
.
store_name
)
end
private
def
create_redis_store
(
options
,
extras
)
::
Redis
::
Store
.
new
(
options
.
merge
(
extras
))
end
end
end
end
end
end
end
spec/lib/gitlab/redis/multi_store_spec.rb
deleted
100644 → 0
View file @
f3a1cbfc
This diff is collapsed.
Click to expand it.
spec/lib/gitlab/redis/sessions_spec.rb
View file @
c66fb99d
...
@@ -6,33 +6,18 @@ RSpec.describe Gitlab::Redis::Sessions do
...
@@ -6,33 +6,18 @@ RSpec.describe Gitlab::Redis::Sessions do
it_behaves_like
"redis_new_instance_shared_examples"
,
'sessions'
,
Gitlab
::
Redis
::
SharedState
it_behaves_like
"redis_new_instance_shared_examples"
,
'sessions'
,
Gitlab
::
Redis
::
SharedState
describe
'redis instance used in connection pool'
do
describe
'redis instance used in connection pool'
do
before
do
around
do
|
example
|
clear_pool
clear_pool
end
example
.
run
ensure
after
do
clear_pool
clear_pool
end
end
context
'when redis.sessions configuration is not provided'
do
it
'uses ::Redis instance'
do
it
'uses ::Redis instance'
do
expect
(
described_class
).
to
receive
(
:config_fallback?
).
and_return
(
true
)
described_class
.
pool
.
with
do
|
redis_instance
|
described_class
.
pool
.
with
do
|
redis_instance
|
expect
(
redis_instance
).
to
be_instance_of
(
::
Redis
)
expect
(
redis_instance
).
to
be_instance_of
(
::
Redis
)
end
end
end
end
end
context
'when redis.sessions configuration is provided'
do
it
'instantiates an instance of MultiStore'
do
expect
(
described_class
).
to
receive
(
:config_fallback?
).
and_return
(
false
)
described_class
.
pool
.
with
do
|
redis_instance
|
expect
(
redis_instance
).
to
be_instance_of
(
::
Gitlab
::
Redis
::
MultiStore
)
end
end
end
def
clear_pool
def
clear_pool
described_class
.
remove_instance_variable
(
:@pool
)
described_class
.
remove_instance_variable
(
:@pool
)
...
@@ -44,49 +29,9 @@ RSpec.describe Gitlab::Redis::Sessions do
...
@@ -44,49 +29,9 @@ RSpec.describe Gitlab::Redis::Sessions do
describe
'#store'
do
describe
'#store'
do
subject
(
:store
)
{
described_class
.
store
(
namespace:
described_class
::
SESSION_NAMESPACE
)
}
subject
(
:store
)
{
described_class
.
store
(
namespace:
described_class
::
SESSION_NAMESPACE
)
}
context
'when redis.sessions configuration is NOT provided'
do
# Check that Gitlab::Redis::Sessions is configured as RedisStore.
it
'instantiates ::Redis instance'
do
it
'instantiates an instance of Redis::Store'
do
expect
(
described_class
).
to
receive
(
:config_fallback?
).
and_return
(
true
)
expect
(
store
).
to
be_instance_of
(
::
Redis
::
Store
)
expect
(
store
).
to
be_instance_of
(
::
Redis
::
Store
)
end
end
end
end
context
'when redis.sessions configuration is provided'
do
let
(
:config_new_format_host
)
{
"spec/fixtures/config/redis_new_format_host.yml"
}
let
(
:config_new_format_socket
)
{
"spec/fixtures/config/redis_new_format_socket.yml"
}
before
do
redis_clear_raw_config!
(
Gitlab
::
Redis
::
Sessions
)
redis_clear_raw_config!
(
Gitlab
::
Redis
::
SharedState
)
allow
(
described_class
).
to
receive
(
:config_fallback?
).
and_return
(
false
)
end
after
do
redis_clear_raw_config!
(
Gitlab
::
Redis
::
Sessions
)
redis_clear_raw_config!
(
Gitlab
::
Redis
::
SharedState
)
end
# Check that Gitlab::Redis::Sessions is configured as MultiStore with proper attrs.
it
'instantiates an instance of MultiStore'
,
:aggregate_failures
do
expect
(
described_class
).
to
receive
(
:config_file_name
).
and_return
(
config_new_format_host
)
expect
(
::
Gitlab
::
Redis
::
SharedState
).
to
receive
(
:config_file_name
).
and_return
(
config_new_format_socket
)
expect
(
store
).
to
be_instance_of
(
::
Gitlab
::
Redis
::
MultiStore
)
expect
(
store
.
primary_store
.
to_s
).
to
eq
(
"Redis Client connected to test-host:6379 against DB 99 with namespace session:gitlab"
)
expect
(
store
.
secondary_store
.
to_s
).
to
eq
(
"Redis Client connected to /path/to/redis.sock against DB 0 with namespace session:gitlab"
)
expect
(
store
.
instance_name
).
to
eq
(
'Sessions'
)
end
context
'when MultiStore correctly configured'
do
before
do
allow
(
described_class
).
to
receive
(
:config_file_name
).
and_return
(
config_new_format_host
)
allow
(
::
Gitlab
::
Redis
::
SharedState
).
to
receive
(
:config_file_name
).
and_return
(
config_new_format_socket
)
end
it_behaves_like
'multi store feature flags'
,
:use_primary_and_secondary_stores_for_sessions
,
:use_primary_store_as_default_for_sessions
end
end
end
end
end
spec/support/shared_examples/lib/gitlab/redis/multi_store_feature_flags_shared_examples.rb
deleted
100644 → 0
View file @
f3a1cbfc
# frozen_string_literal: true
RSpec
.
shared_examples
'multi store feature flags'
do
|
use_primary_and_secondary_stores
,
use_primary_store_as_default
|
context
"with feature flag :
#{
use_primary_and_secondary_stores
}
is enabled"
do
before
do
stub_feature_flags
(
use_primary_and_secondary_stores
=>
true
)
end
it
'multi store is enabled'
do
expect
(
subject
.
use_primary_and_secondary_stores?
).
to
be
true
end
end
context
"with feature flag :
#{
use_primary_and_secondary_stores
}
is disabled"
do
before
do
stub_feature_flags
(
use_primary_and_secondary_stores
=>
false
)
end
it
'multi store is disabled'
do
expect
(
subject
.
use_primary_and_secondary_stores?
).
to
be
false
end
end
context
"with feature flag :
#{
use_primary_store_as_default
}
is enabled"
do
before
do
stub_feature_flags
(
use_primary_store_as_default
=>
true
)
end
it
'primary store is enabled'
do
expect
(
subject
.
use_primary_store_as_default?
).
to
be
true
end
end
context
"with feature flag :
#{
use_primary_store_as_default
}
is disabled"
do
before
do
stub_feature_flags
(
use_primary_store_as_default
=>
false
)
end
it
'primary store is disabled'
do
expect
(
subject
.
use_primary_store_as_default?
).
to
be
false
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment