Use etag caching for environments JSON
For the index view, the environments can now be requested every 15 seconds. Any transition state of a projects environments will trigger a cache invalidation action. Fixes gitlab-org/gitlab-ce#31701
This commit is contained in:
parent
50a0044228
commit
ebede2b3ff
|
@ -15,6 +15,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html
|
format.html
|
||||||
format.json do
|
format.json do
|
||||||
|
Gitlab::PollingInterval.set_header(response, interval: 15_000)
|
||||||
|
|
||||||
render json: {
|
render json: {
|
||||||
environments: EnvironmentSerializer
|
environments: EnvironmentSerializer
|
||||||
.new(project: @project, current_user: @current_user)
|
.new(project: @project, current_user: @current_user)
|
||||||
|
|
|
@ -57,6 +57,10 @@ class Environment < ActiveRecord::Base
|
||||||
|
|
||||||
state :available
|
state :available
|
||||||
state :stopped
|
state :stopped
|
||||||
|
|
||||||
|
after_transition do |environment|
|
||||||
|
environment.expire_etag_cache
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def predefined_variables
|
def predefined_variables
|
||||||
|
@ -196,6 +200,13 @@ class Environment < ActiveRecord::Base
|
||||||
[external_url, public_path].join('/')
|
[external_url, public_path].join('/')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def expire_etag_cache
|
||||||
|
Gitlab::EtagCaching::Store.new.tap do |store|
|
||||||
|
store.touch(Gitlab::Routing.url_helpers
|
||||||
|
.namespace_project_environments_path(project.namespace, project))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Slugifying a name may remove the uniqueness guarantee afforded by it being
|
# Slugifying a name may remove the uniqueness guarantee afforded by it being
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Make environment table realtime
|
||||||
|
merge_request: 11333
|
||||||
|
author:
|
|
@ -7,9 +7,10 @@ module Gitlab
|
||||||
# - Don't contain a reserved word (expect for the words used in the
|
# - Don't contain a reserved word (expect for the words used in the
|
||||||
# regex itself)
|
# regex itself)
|
||||||
# - Ending in `noteable/issue/<id>/notes` for the `issue_notes` route
|
# - Ending in `noteable/issue/<id>/notes` for the `issue_notes` route
|
||||||
# - Ending in `issues/id`/realtime_changes` for the `issue_title` route
|
# - Ending in `issues/id`/rendered_title` for the `issue_title` route
|
||||||
USED_IN_ROUTES = %w[noteable issue notes issues realtime_changes
|
USED_IN_ROUTES = %w[noteable issue notes issues realtime_changes
|
||||||
commit pipelines merge_requests new].freeze
|
commit pipelines merge_requests new
|
||||||
|
environments].freeze
|
||||||
RESERVED_WORDS = DynamicPathValidator::WILDCARD_ROUTES - USED_IN_ROUTES
|
RESERVED_WORDS = DynamicPathValidator::WILDCARD_ROUTES - USED_IN_ROUTES
|
||||||
RESERVED_WORDS_REGEX = Regexp.union(*RESERVED_WORDS)
|
RESERVED_WORDS_REGEX = Regexp.union(*RESERVED_WORDS)
|
||||||
ROUTES = [
|
ROUTES = [
|
||||||
|
@ -40,6 +41,10 @@ module Gitlab
|
||||||
Gitlab::EtagCaching::Router::Route.new(
|
Gitlab::EtagCaching::Router::Route.new(
|
||||||
%r(^(?!.*(#{RESERVED_WORDS})).*/pipelines/\d+\.json\z),
|
%r(^(?!.*(#{RESERVED_WORDS})).*/pipelines/\d+\.json\z),
|
||||||
'project_pipeline'
|
'project_pipeline'
|
||||||
|
),
|
||||||
|
Gitlab::EtagCaching::Router::Route.new(
|
||||||
|
%r(^(?!.*(#{RESERVED_WORDS_REGEX})).*/environments\.json\z),
|
||||||
|
'environments'
|
||||||
)
|
)
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,16 @@ describe Gitlab::EtagCaching::Router do
|
||||||
expect(result).to be_blank
|
expect(result).to be_blank
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'matches the environments path' do
|
||||||
|
env = build_env(
|
||||||
|
'/my-group/my-project/environments.json'
|
||||||
|
)
|
||||||
|
|
||||||
|
result = described_class.match(env)
|
||||||
|
|
||||||
|
expect(result).to be_blank
|
||||||
|
end
|
||||||
|
|
||||||
def build_env(path)
|
def build_env(path)
|
||||||
{ 'PATH_INFO' => path }
|
{ 'PATH_INFO' => path }
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Environment, models: true do
|
describe Environment, models: true do
|
||||||
let(:project) { create(:empty_project) }
|
set(:project) { create(:empty_project) }
|
||||||
subject(:environment) { create(:environment, project: project) }
|
subject(:environment) { create(:environment, project: project) }
|
||||||
|
|
||||||
it { is_expected.to belong_to(:project) }
|
it { is_expected.to belong_to(:project) }
|
||||||
|
@ -34,6 +34,14 @@ describe Environment, models: true do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'state machine' do
|
||||||
|
it 'invalidates the cache after a change' do
|
||||||
|
expect(environment).to receive(:expire_etag_cache)
|
||||||
|
|
||||||
|
environment.stop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#nullify_external_url' do
|
describe '#nullify_external_url' do
|
||||||
it 'replaces a blank url with nil' do
|
it 'replaces a blank url with nil' do
|
||||||
env = build(:environment, external_url: "")
|
env = build(:environment, external_url: "")
|
||||||
|
|
Loading…
Reference in New Issue