Skip to content
Snippets Groups Projects
Commit 9543025e authored by Adam Niedzielski's avatar Adam Niedzielski
Browse files

Introduce "polling_interval_multiplier" as application setting

Implement module for setting "Poll-Interval" response header.
Return 429 in ETag caching middleware when polling is disabled.
parent 2faf955c
No related branches found
No related tags found
No related merge requests found
Showing with 146 additions and 7 deletions
Loading
Loading
@@ -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: [],
Loading
Loading
Loading
Loading
@@ -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)
Loading
Loading
@@ -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
 
Loading
Loading
Loading
Loading
@@ -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'
---
title: Introduce "polling_interval_multiplier" as application setting
merge_request: 10280
author:
# 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
Loading
Loading
@@ -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"
Loading
Loading
@@ -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|
Loading
Loading
Loading
Loading
@@ -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
}
```
 
Loading
Loading
@@ -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
Loading
Loading
@@ -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
}
```
Loading
Loading
@@ -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
Loading
Loading
Loading
Loading
@@ -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,
Loading
Loading
@@ -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)
Loading
Loading
Loading
Loading
@@ -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)
 
Loading
Loading
@@ -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)
Loading
Loading
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
Loading
Loading
@@ -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
Loading
Loading
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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment