From ebede2b3ff1c2b089529c4f9d6268641580e280b Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Fri, 12 May 2017 15:19:27 +0200 Subject: [PATCH] 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 --- app/controllers/projects/environments_controller.rb | 2 ++ app/models/environment.rb | 11 +++++++++++ changelogs/unreleased/zj-realtime-env-list.yml | 4 ++++ lib/gitlab/etag_caching/router.rb | 9 +++++++-- spec/lib/gitlab/etag_caching/router_spec.rb | 10 ++++++++++ spec/models/environment_spec.rb | 10 +++++++++- 6 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/zj-realtime-env-list.yml diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index fd57afbd05f..537c74d5231 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -15,6 +15,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController respond_to do |format| format.html format.json do + Gitlab::PollingInterval.set_header(response, interval: 15_000) + render json: { environments: EnvironmentSerializer .new(project: @project, current_user: @current_user) diff --git a/app/models/environment.rb b/app/models/environment.rb index 61572d8d69a..07722d9a59e 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -57,6 +57,10 @@ class Environment < ActiveRecord::Base state :available state :stopped + + after_transition do |environment| + environment.expire_etag_cache + end end def predefined_variables @@ -196,6 +200,13 @@ class Environment < ActiveRecord::Base [external_url, public_path].join('/') 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 # Slugifying a name may remove the uniqueness guarantee afforded by it being diff --git a/changelogs/unreleased/zj-realtime-env-list.yml b/changelogs/unreleased/zj-realtime-env-list.yml new file mode 100644 index 00000000000..6460d17edc9 --- /dev/null +++ b/changelogs/unreleased/zj-realtime-env-list.yml @@ -0,0 +1,4 @@ +--- +title: Make environment table realtime +merge_request: 11333 +author: diff --git a/lib/gitlab/etag_caching/router.rb b/lib/gitlab/etag_caching/router.rb index ba31041d0c1..01bf578c570 100644 --- a/lib/gitlab/etag_caching/router.rb +++ b/lib/gitlab/etag_caching/router.rb @@ -7,9 +7,10 @@ module Gitlab # - Don't contain a reserved word (expect for the words used in the # regex itself) # - Ending in `noteable/issue//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 - commit pipelines merge_requests new].freeze + commit pipelines merge_requests new + environments].freeze RESERVED_WORDS = DynamicPathValidator::WILDCARD_ROUTES - USED_IN_ROUTES RESERVED_WORDS_REGEX = Regexp.union(*RESERVED_WORDS) ROUTES = [ @@ -40,6 +41,10 @@ module Gitlab Gitlab::EtagCaching::Router::Route.new( %r(^(?!.*(#{RESERVED_WORDS})).*/pipelines/\d+\.json\z), 'project_pipeline' + ), + Gitlab::EtagCaching::Router::Route.new( + %r(^(?!.*(#{RESERVED_WORDS_REGEX})).*/environments\.json\z), + 'environments' ) ].freeze diff --git a/spec/lib/gitlab/etag_caching/router_spec.rb b/spec/lib/gitlab/etag_caching/router_spec.rb index 5ae4a19263c..456bd9898ea 100644 --- a/spec/lib/gitlab/etag_caching/router_spec.rb +++ b/spec/lib/gitlab/etag_caching/router_spec.rb @@ -77,6 +77,16 @@ describe Gitlab::EtagCaching::Router do expect(result).to be_blank 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) { 'PATH_INFO' => path } end diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 12519de8636..768f557bb9f 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Environment, models: true do - let(:project) { create(:empty_project) } + set(:project) { create(:empty_project) } subject(:environment) { create(:environment, project: project) } it { is_expected.to belong_to(:project) } @@ -34,6 +34,14 @@ describe Environment, models: true do 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 it 'replaces a blank url with nil' do env = build(:environment, external_url: "")