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
0
Merge Requests
0
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
Boxiang Sun
gitlab-ce
Commits
02f17a09
Commit
02f17a09
authored
May 04, 2018
by
Rémy Coutable
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Introduce a new CacheableAttributes concern
Signed-off-by:
Rémy Coutable
<
remy@rymai.me
>
parent
a2dbca4a
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
211 additions
and
0 deletions
+211
-0
app/models/concerns/cacheable_attributes.rb
app/models/concerns/cacheable_attributes.rb
+54
-0
lib/gitlab.rb
lib/gitlab.rb
+4
-0
spec/models/concerns/cacheable_attributes_spec.rb
spec/models/concerns/cacheable_attributes_spec.rb
+153
-0
No files found.
app/models/concerns/cacheable_attributes.rb
0 → 100644
View file @
02f17a09
module
CacheableAttributes
extend
ActiveSupport
::
Concern
included
do
after_commit
{
self
.
class
.
expire
}
end
class_methods
do
# Can be overriden
def
current_without_cache
last
end
def
cache_key
"
#{
name
}
:
#{
Gitlab
::
VERSION
}
:
#{
Gitlab
.
migrations_hash
}
:json"
.
freeze
end
def
defaults
{}
end
def
build_from_defaults
(
attributes
=
{})
new
(
defaults
.
merge
(
attributes
))
end
def
cached
json_attributes
=
Rails
.
cache
.
read
(
cache_key
)
return
nil
unless
json_attributes
.
present?
build_from_defaults
(
JSON
.
parse
(
json_attributes
))
end
def
current
cached_record
=
cached
return
cached_record
if
cached_record
.
present?
current_without_cache
.
tap
{
|
current_record
|
current_record
&
.
cache!
}
rescue
# Fall back to an uncached value if there are any problems (e.g. Redis down)
current_without_cache
end
def
expire
Rails
.
cache
.
delete
(
cache_key
)
rescue
# Gracefully handle when Redis is not available. For example,
# omnibus may fail here during gitlab:assets:compile.
end
end
def
cache!
Rails
.
cache
.
write
(
self
.
class
.
cache_key
,
attributes
.
to_json
)
end
end
lib/gitlab.rb
View file @
02f17a09
...
...
@@ -9,6 +9,10 @@ module Gitlab
Settings
end
def
self
.
migrations_hash
@_migrations_hash
||=
Digest
::
MD5
.
hexdigest
(
ActiveRecord
::
Migrator
.
get_all_versions
.
to_s
)
end
COM_URL
=
'https://gitlab.com'
.
freeze
APP_DIRS_PATTERN
=
%r{^/?(app|config|ee|lib|spec|
\(\w
*
\)
)}
SUBDOMAIN_REGEX
=
%r{
\A
https://[a-z0-9]+
\.
gitlab
\.
com
\z
}
...
...
spec/models/concerns/cacheable_attributes_spec.rb
0 → 100644
View file @
02f17a09
require
'spec_helper'
describe
CacheableAttributes
do
let
(
:minimal_test_class
)
do
Class
.
new
do
include
ActiveModel
::
Model
extend
ActiveModel
::
Callbacks
define_model_callbacks
:commit
include
CacheableAttributes
def
self
.
name
'TestClass'
end
def
self
.
first
@_first
||=
new
(
'foo'
=>
'a'
)
end
def
self
.
last
@_last
||=
new
(
'foo'
=>
'a'
,
'bar'
=>
'b'
)
end
attr_accessor
:attributes
def
initialize
(
attrs
=
{})
@attributes
=
attrs
end
end
end
shared_context
'with defaults'
do
before
do
minimal_test_class
.
define_singleton_method
(
:defaults
)
do
{
foo:
'a'
,
bar:
'b'
,
baz:
'c'
}
end
end
end
describe
'.current_without_cache'
do
it
'defaults to last'
do
expect
(
minimal_test_class
.
current_without_cache
).
to
eq
(
minimal_test_class
.
last
)
end
it
'can be overriden'
do
minimal_test_class
.
define_singleton_method
(
:current_without_cache
)
do
first
end
expect
(
minimal_test_class
.
current_without_cache
).
to
eq
(
minimal_test_class
.
first
)
end
end
describe
'.cache_key'
do
it
'excludes cache attributes'
do
expect
(
minimal_test_class
.
cache_key
).
to
eq
(
"TestClass:
#{
Gitlab
::
VERSION
}
:
#{
Gitlab
.
migrations_hash
}
:json"
)
end
end
describe
'.defaults'
do
it
'defaults to {}'
do
expect
(
minimal_test_class
.
defaults
).
to
eq
({})
end
context
'with defaults defined'
do
include_context
'with defaults'
it
'can be overriden'
do
expect
(
minimal_test_class
.
defaults
).
to
eq
({
foo:
'a'
,
bar:
'b'
,
baz:
'c'
})
end
end
end
describe
'.build_from_defaults'
do
include_context
'with defaults'
context
'without any attributes given'
do
it
'intializes a new object with the defaults'
do
expect
(
minimal_test_class
.
build_from_defaults
).
not_to
be_persisted
end
end
context
'without attributes given'
do
it
'intializes a new object with the given attributes merged into the defaults'
do
expect
(
minimal_test_class
.
build_from_defaults
(
foo:
'd'
).
attributes
[
:foo
]).
to
eq
(
'd'
)
end
end
end
describe
'.current'
,
:use_clean_rails_memory_store_caching
do
context
'redis unavailable'
do
it
'returns an uncached record'
do
allow
(
minimal_test_class
).
to
receive
(
:last
).
and_return
(
:last
)
expect
(
Rails
.
cache
).
to
receive
(
:read
).
and_raise
(
Redis
::
BaseError
)
expect
(
minimal_test_class
.
current
).
to
eq
(
:last
)
end
end
context
'when a record is not yet present'
do
it
'does not cache nil object'
do
# when missing settings a nil object is returned, but not cached
allow
(
minimal_test_class
).
to
receive
(
:last
).
twice
.
and_return
(
nil
)
expect
(
minimal_test_class
.
current
).
to
be_nil
expect
(
Rails
.
cache
.
exist?
(
minimal_test_class
.
cache_key
)).
to
be
(
false
)
end
it
'cache non-nil object'
do
# when the settings are set the method returns a valid object
allow
(
minimal_test_class
).
to
receive
(
:last
).
and_call_original
expect
(
minimal_test_class
.
current
).
to
eq
(
minimal_test_class
.
last
)
expect
(
Rails
.
cache
.
exist?
(
minimal_test_class
.
cache_key
)).
to
be
(
true
)
# subsequent calls retrieve the record from the cache
last_record
=
minimal_test_class
.
last
expect
(
minimal_test_class
).
not_to
receive
(
:last
)
expect
(
minimal_test_class
.
current
.
attributes
).
to
eq
(
last_record
.
attributes
)
end
end
end
describe
'.cached'
,
:use_clean_rails_memory_store_caching
do
context
'when cache is cold'
do
it
'returns nil'
do
expect
(
minimal_test_class
.
cached
).
to
be_nil
end
end
context
'when cached settings do not include the latest defaults'
do
before
do
Rails
.
cache
.
write
(
minimal_test_class
.
cache_key
,
{
bar:
'b'
,
baz:
'c'
}.
to_json
)
minimal_test_class
.
define_singleton_method
(
:defaults
)
do
{
foo:
'a'
,
bar:
'b'
,
baz:
'c'
}
end
end
it
'includes attributes from defaults'
do
expect
(
minimal_test_class
.
cached
.
attributes
[
:foo
]).
to
eq
(
minimal_test_class
.
defaults
[
:foo
])
end
end
end
describe
'#cache!'
,
:use_clean_rails_memory_store_caching
do
let
(
:appearance_record
)
{
create
(
:appearance
)
}
it
'caches the attributes'
do
appearance_record
.
cache!
expect
(
Rails
.
cache
.
read
(
Appearance
.
cache_key
)).
to
eq
(
appearance_record
.
attributes
.
to_json
)
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