Commit a2204ab2 authored by Kerri Miller's avatar Kerri Miller

Merge branch 'jv-etag-annotations' into 'master'

Annotate Etag cache hits with caller_id

See merge request gitlab-org/gitlab!81303
parents 6d582ea0 78737f81
...@@ -4,14 +4,15 @@ module EE ...@@ -4,14 +4,15 @@ module EE
module Gitlab module Gitlab
module EtagCaching module EtagCaching
module Router module Router
module Restful module Rails
extend ActiveSupport::Concern extend ActiveSupport::Concern
EE_ROUTE_DEFINITONS = [ EE_ROUTE_DEFINITONS = [
[ [
%r(^/groups/#{::Gitlab::PathRegex.full_namespace_route_regex}/-/epics/\d+/notes\z), %r(^/groups/#{::Gitlab::PathRegex.full_namespace_route_regex}/-/epics/\d+/notes\z),
'epic_notes', 'epic_notes',
'portfolio_management' ::Groups::Epics::NotesController,
:index
] ]
].freeze ].freeze
...@@ -28,7 +29,7 @@ module EE ...@@ -28,7 +29,7 @@ module EE
end end
def ee_routes def ee_routes
EE_ROUTE_DEFINITONS.map(&method(:build_route)) EE_ROUTE_DEFINITONS.map(&method(:build_rails_route))
end end
end end
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::EtagCaching::Router::Restful do RSpec.describe Gitlab::EtagCaching::Router::Rails do
it 'matches epic notes endpoint' do it 'matches epic notes endpoint' do
result = described_class.match( result = described_class.match(
double(path_info: '/groups/my-group/and-subgroup/-/epics/1/notes') double(path_info: '/groups/my-group/and-subgroup/-/epics/1/notes')
......
...@@ -67,7 +67,10 @@ module Gitlab ...@@ -67,7 +67,10 @@ module Gitlab
add_instrument_for_cache_hit(status_code, route, request) add_instrument_for_cache_hit(status_code, route, request)
Gitlab::ApplicationContext.push(feature_category: route.feature_category) Gitlab::ApplicationContext.push(
feature_category: route.feature_category,
caller_id: route.caller_id
)
new_headers = { new_headers = {
'ETag' => etag, 'ETag' => etag,
......
...@@ -3,22 +3,33 @@ ...@@ -3,22 +3,33 @@
module Gitlab module Gitlab
module EtagCaching module EtagCaching
module Router module Router
Route = Struct.new(:regexp, :name, :feature_category, :router) do Route = Struct.new(:router, :regexp, :name, :feature_category, :caller_id) do
delegate :match, to: :regexp delegate :match, to: :regexp
delegate :cache_key, to: :router delegate :cache_key, to: :router
end end
module Helpers module Helpers
def build_route(attrs) def build_route(attrs)
EtagCaching::Router::Route.new(*attrs, self) EtagCaching::Router::Route.new(self, *attrs)
end
def build_rails_route(attrs)
regexp, name, controller, action_name = *attrs
EtagCaching::Router::Route.new(
self,
regexp,
name,
controller.feature_category_for_action(action_name).to_s,
controller.endpoint_id_for_action(action_name).to_s
)
end end
end end
# Performing RESTful routing match before GraphQL would be more expensive # Performing Rails routing match before GraphQL would be more expensive
# for the GraphQL requests because we need to traverse all of the RESTful # for the GraphQL requests because we need to traverse all of the RESTful
# route definitions before falling back to GraphQL. # route definitions before falling back to GraphQL.
def self.match(request) def self.match(request)
Router::Graphql.match(request) || Router::Restful.match(request) Router::Graphql.match(request) || Router::Rails.match(request)
end end
end end
end end
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Gitlab module Gitlab
module EtagCaching module EtagCaching
module Router module Router
class Restful class Rails
extend EtagCaching::Router::Helpers extend EtagCaching::Router::Helpers
# We enable an ETag for every request matching the regex. # We enable an ETag for every request matching the regex.
...@@ -23,74 +23,88 @@ module Gitlab ...@@ -23,74 +23,88 @@ module Gitlab
[ [
%r(#{RESERVED_WORDS_PREFIX}/noteable/issue/\d+/notes\z), %r(#{RESERVED_WORDS_PREFIX}/noteable/issue/\d+/notes\z),
'issue_notes', 'issue_notes',
'team_planning' ::Projects::NotesController,
:index
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/noteable/merge_request/\d+/notes\z), %r(#{RESERVED_WORDS_PREFIX}/noteable/merge_request/\d+/notes\z),
'merge_request_notes', 'merge_request_notes',
'code_review' ::Projects::NotesController,
:index
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/issues/\d+/realtime_changes\z), %r(#{RESERVED_WORDS_PREFIX}/issues/\d+/realtime_changes\z),
'issue_title', 'issue_title',
'team_planning' ::Projects::IssuesController,
:realtime_changes
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/commit/\S+/pipelines\.json\z), %r(#{RESERVED_WORDS_PREFIX}/commit/\S+/pipelines\.json\z),
'commit_pipelines', 'commit_pipelines',
'continuous_integration' ::Projects::CommitController,
:pipelines
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/merge_requests/new\.json\z), %r(#{RESERVED_WORDS_PREFIX}/merge_requests/new\.json\z),
'new_merge_request_pipelines', 'new_merge_request_pipelines',
'continuous_integration' ::Projects::MergeRequests::CreationsController,
:new
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/merge_requests/\d+/pipelines\.json\z), %r(#{RESERVED_WORDS_PREFIX}/merge_requests/\d+/pipelines\.json\z),
'merge_request_pipelines', 'merge_request_pipelines',
'continuous_integration' ::Projects::MergeRequestsController,
:pipelines
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/pipelines\.json\z), %r(#{RESERVED_WORDS_PREFIX}/pipelines\.json\z),
'project_pipelines', 'project_pipelines',
'continuous_integration' ::Projects::PipelinesController,
:index
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/pipelines/\d+\.json\z), %r(#{RESERVED_WORDS_PREFIX}/pipelines/\d+\.json\z),
'project_pipeline', 'project_pipeline',
'continuous_integration' ::Projects::PipelinesController,
:show
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/builds/\d+\.json\z), %r(#{RESERVED_WORDS_PREFIX}/builds/\d+\.json\z),
'project_build', 'project_build',
'continuous_integration' ::Projects::BuildsController,
:show
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/clusters/\d+/environments\z), %r(#{RESERVED_WORDS_PREFIX}/clusters/\d+/environments\z),
'cluster_environments', 'cluster_environments',
'continuous_delivery' ::Groups::ClustersController,
:environments
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/-/environments\.json\z), %r(#{RESERVED_WORDS_PREFIX}/-/environments\.json\z),
'environments', 'environments',
'continuous_delivery' ::Projects::EnvironmentsController,
:index
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/import/github/realtime_changes\.json\z), %r(#{RESERVED_WORDS_PREFIX}/import/github/realtime_changes\.json\z),
'realtime_changes_import_github', 'realtime_changes_import_github',
'importers' ::Import::GithubController,
:realtime_changes
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/import/gitea/realtime_changes\.json\z), %r(#{RESERVED_WORDS_PREFIX}/import/gitea/realtime_changes\.json\z),
'realtime_changes_import_gitea', 'realtime_changes_import_gitea',
'importers' ::Import::GiteaController,
:realtime_changes
], ],
[ [
%r(#{RESERVED_WORDS_PREFIX}/merge_requests/\d+/cached_widget\.json\z), %r(#{RESERVED_WORDS_PREFIX}/merge_requests/\d+/cached_widget\.json\z),
'merge_request_widget', 'merge_request_widget',
'code_review' ::Projects::MergeRequests::ContentController,
:cached_widget
] ]
].map(&method(:build_route)).freeze ].map(&method(:build_rails_route)).freeze
# Overridden in EE to add more routes # Overridden in EE to add more routes
def self.all_routes def self.all_routes
...@@ -109,4 +123,4 @@ module Gitlab ...@@ -109,4 +123,4 @@ module Gitlab
end end
end end
Gitlab::EtagCaching::Router::Restful.prepend_mod_with('Gitlab::EtagCaching::Router::Restful') Gitlab::EtagCaching::Router::Rails.prepend_mod_with('Gitlab::EtagCaching::Router::Rails')
...@@ -174,7 +174,8 @@ RSpec.describe Gitlab::EtagCaching::Middleware, :clean_gitlab_redis_shared_state ...@@ -174,7 +174,8 @@ RSpec.describe Gitlab::EtagCaching::Middleware, :clean_gitlab_redis_shared_state
it "pushes route's feature category to the context" do it "pushes route's feature category to the context" do
expect(Gitlab::ApplicationContext).to receive(:push).with( expect(Gitlab::ApplicationContext).to receive(:push).with(
feature_category: 'team_planning' feature_category: 'team_planning',
caller_id: 'Projects::NotesController#index'
) )
_, _, _ = middleware.call(build_request(path, if_none_match)) _, _, _ = middleware.call(build_request(path, if_none_match))
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::EtagCaching::Router::Restful do RSpec.describe Gitlab::EtagCaching::Router::Rails do
it 'matches issue notes endpoint' do it 'matches issue notes endpoint' do
result = match_route('/my-group/and-subgroup/here-comes-the-project/noteable/issue/1/notes') result = match_route('/my-group/and-subgroup/here-comes-the-project/noteable/issue/1/notes')
...@@ -114,6 +114,12 @@ RSpec.describe Gitlab::EtagCaching::Router::Restful do ...@@ -114,6 +114,12 @@ RSpec.describe Gitlab::EtagCaching::Router::Restful do
end end
end end
it 'has a caller_id for every route', :aggregate_failures do
described_class::ROUTES.each do |route|
expect(route.caller_id).to include('#'), "#{route.name} has caller_id #{route.caller_id}, which is not valid"
end
end
def match_route(path) def match_route(path)
described_class.match(double(path_info: path)) described_class.match(double(path_info: path))
end end
......
...@@ -10,7 +10,7 @@ RSpec.describe Gitlab::EtagCaching::Router do ...@@ -10,7 +10,7 @@ RSpec.describe Gitlab::EtagCaching::Router do
expect(result).to be_present expect(result).to be_present
expect(result.name).to eq 'project_pipelines' expect(result.name).to eq 'project_pipelines'
expect(result.router).to eq Gitlab::EtagCaching::Router::Restful expect(result.router).to eq Gitlab::EtagCaching::Router::Rails
end 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