Merge branch 'introduce-base-polling-interval' into 'master'

Introduce "polling_interval_multiplier" as application setting

Closes #29759

See merge request !10280
This commit is contained in:
Sean McGivern 2017-04-03 14:51:37 +00:00
commit 872b3215d2
13 changed files with 146 additions and 7 deletions

View File

@ -134,6 +134,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:unique_ips_limit_enabled,
:version_check_enabled,
:terminal_max_session_time,
:polling_interval_multiplier,
disabled_oauth_sign_in_sources: [],
import_sources: [],

View File

@ -131,6 +131,10 @@ class ApplicationSetting < ActiveRecord::Base
presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :polling_interval_multiplier,
presence: true,
numericality: { greater_than_or_equal_to: 0 }
validates_each :restricted_visibility_levels do |record, attr, value|
value&.each do |level|
unless Gitlab::VisibilityLevel.options.has_value?(level)
@ -233,7 +237,8 @@ class ApplicationSetting < ActiveRecord::Base
signup_enabled: Settings.gitlab['signup_enabled'],
terminal_max_session_time: 0,
two_factor_grace_period: 48,
user_default_external: false
user_default_external: false,
polling_interval_multiplier: 1
}
end

View File

@ -558,5 +558,19 @@
Maximum time for web terminal websocket connection (in seconds).
0 for unlimited.
%fieldset
%legend Real-time features
.form-group
= f.label :polling_interval_multiplier, 'Polling interval multiplier', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :polling_interval_multiplier, class: 'form-control'
.help-block
Change this value to influence how frequently the GitLab UI polls for updates.
If you set the value to 2 all polling intervals are multiplied
by 2, which means that polling happens half as frequently.
The multiplier can also have a decimal value.
The default value (1) is a reasonable choice for the majority of GitLab
installations. Set to 0 to completely disable polling.
.form-actions
= f.submit 'Save', class: 'btn btn-save'

View File

@ -0,0 +1,4 @@
---
title: Introduce "polling_interval_multiplier" as application setting
merge_request: 10280
author:

View File

@ -0,0 +1,33 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddPollingIntervalMultiplierToApplicationSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
# When a migration requires downtime you **must** uncomment the following
# constant and define a short and easy to understand explanation as to why the
# migration requires downtime.
# DOWNTIME_REASON = ''
# When using the methods "add_concurrent_index" or "add_column_with_default"
# you must disable the use of transactions as these methods can not run in an
# existing transaction. When using "add_concurrent_index" make sure that this
# method is the _only_ method called in the migration, any other changes
# should go in a separate migration. This ensures that upon failure _only_ the
# index creation fails and can be retried or reverted easily.
#
# To disable transactions uncomment the following line and remove these
# comments:
disable_ddl_transaction!
def up
add_column_with_default :application_settings, :polling_interval_multiplier, :decimal, default: 1, allow_null: false
end
def down
remove_column :application_settings, :polling_interval_multiplier
end
end

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170317203554) do
ActiveRecord::Schema.define(version: 20170329124448) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -115,6 +115,7 @@ ActiveRecord::Schema.define(version: 20170317203554) do
t.integer "unique_ips_limit_per_user"
t.integer "unique_ips_limit_time_window"
t.boolean "unique_ips_limit_enabled", default: false, null: false
t.decimal "polling_interval_multiplier", default: 1.0, null: false
end
create_table "audit_events", force: :cascade do |t|

View File

@ -48,7 +48,8 @@ Example response:
"koding_url": null,
"plantuml_enabled": false,
"plantuml_url": null,
"terminal_max_session_time": 0
"terminal_max_session_time": 0,
"polling_interval_multiplier": 1.0
}
```
@ -88,6 +89,7 @@ PUT /application/settings
| `plantuml_enabled` | boolean | no | Enable PlantUML integration. Default is `false`. |
| `plantuml_url` | string | yes (if `plantuml_enabled` is `true`) | The PlantUML instance URL for integration. |
| `terminal_max_session_time` | integer | no | Maximum time for web terminal websocket connection (in seconds). Set to 0 for unlimited time. |
| `polling_interval_multiplier` | decimal | no | Interval multiplier used by endpoints that perform polling. Set to 0 to disable polling. |
```bash
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/application/settings?signup_enabled=false&default_project_visibility=internal
@ -124,6 +126,7 @@ Example response:
"koding_url": null,
"plantuml_enabled": false,
"plantuml_url": null,
"terminal_max_session_time": 0
"terminal_max_session_time": 0,
"polling_interval_multiplier": 1.0
}
```

View File

@ -581,6 +581,7 @@ module API
expose :plantuml_enabled
expose :plantuml_url
expose :terminal_max_session_time
expose :polling_interval_multiplier
end
class Release < Grape::Entity

View File

@ -110,6 +110,7 @@ module API
requires :housekeeping_gc_period, type: Integer, desc: "Number of Git pushes after which 'git gc' is run."
end
optional :terminal_max_session_time, type: Integer, desc: 'Maximum time for web terminal websocket connection (in seconds). Set to 0 for unlimited time.'
optional :polling_interval_multiplier, type: BigDecimal, desc: 'Interval multiplier used by endpoints that perform polling. Set to 0 to disable polling.'
at_least_one_of :default_branch_protection, :default_project_visibility, :default_snippet_visibility,
:default_group_visibility, :restricted_visibility_levels, :import_sources,
:enabled_git_access_protocol, :gravatar_enabled, :default_projects_limit,
@ -125,7 +126,7 @@ module API
:akismet_enabled, :admin_notification_email, :sentry_enabled,
:repository_storage, :repository_checks_enabled, :koding_enabled, :plantuml_enabled,
:version_check_enabled, :email_author_in_body, :html_emails_enabled,
:housekeeping_enabled, :terminal_max_session_time
:housekeeping_enabled, :terminal_max_session_time, :polling_interval_multiplier
end
put "application/settings" do
attrs = declared_params(include_missing: false)

View File

@ -18,8 +18,7 @@ module Gitlab
if_none_match = env['HTTP_IF_NONE_MATCH']
if if_none_match == etag
Gitlab::Metrics.add_event(:etag_caching_cache_hit)
[304, { 'ETag' => etag }, ['']]
handle_cache_hit(etag)
else
track_cache_miss(if_none_match, cached_value_present)
@ -52,6 +51,14 @@ module Gitlab
%Q{W/"#{value}"}
end
def handle_cache_hit(etag)
Gitlab::Metrics.add_event(:etag_caching_cache_hit)
status_code = Gitlab::PollingInterval.polling_enabled? ? 304 : 429
[status_code, { 'ETag' => etag }, ['']]
end
def track_cache_miss(if_none_match, cached_value_present)
if if_none_match.blank?
Gitlab::Metrics.add_event(:etag_caching_header_missing)

View File

@ -0,0 +1,22 @@
module Gitlab
class PollingInterval
include Gitlab::CurrentSettings
HEADER_NAME = 'Poll-Interval'.freeze
def self.set_header(response, interval:)
if polling_enabled?
multiplier = current_application_settings.polling_interval_multiplier
value = (interval * multiplier).to_i
else
value = -1
end
response.headers[HEADER_NAME] = value
end
def self.polling_enabled?
!current_application_settings.polling_interval_multiplier.zero?
end
end
end

View File

@ -99,6 +99,19 @@ describe Gitlab::EtagCaching::Middleware do
middleware.call(build_env(path, if_none_match))
end
context 'when polling is disabled' do
before do
allow(Gitlab::PollingInterval).to receive(:polling_enabled?).
and_return(false)
end
it 'returns status code 429' do
status, _, _ = middleware.call(build_env(path, if_none_match))
expect(status).to eq 429
end
end
end
context 'when If-None-Match header does not match ETag in store' do

View File

@ -0,0 +1,34 @@
require 'spec_helper'
describe Gitlab::PollingInterval, lib: true do
let(:polling_interval) { described_class }
describe '.set_header' do
let(:headers) { {} }
let(:response) { double(headers: headers) }
context 'when polling is disabled' do
before do
stub_application_setting(polling_interval_multiplier: 0)
end
it 'sets value to -1' do
polling_interval.set_header(response, interval: 10_000)
expect(headers['Poll-Interval']).to eq(-1)
end
end
context 'when polling is enabled' do
before do
stub_application_setting(polling_interval_multiplier: 0.33333)
end
it 'applies modifier to base interval' do
polling_interval.set_header(response, interval: 10_000)
expect(headers['Poll-Interval']).to eq(3333)
end
end
end
end