Commit 45c31365 authored by Peter Leitzen's avatar Peter Leitzen

Merge branch 'mount-actioncable-engine-always' into 'master'

Enable real-time issue assignees by default

See merge request gitlab-org/gitlab!71953
parents 1ba710a9 099f9e0e
......@@ -48,9 +48,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
before_action only: :show do
real_time_enabled = Gitlab::ActionCable::Config.in_app? || Feature.enabled?(:real_time_issue_sidebar, @project)
push_to_gon_attributes(:features, :real_time_issue_sidebar, real_time_enabled)
push_frontend_feature_flag(:real_time_issue_sidebar, @project, default_enabled: :yaml)
push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml)
push_frontend_feature_flag(:issue_assignees_widget, @project, default_enabled: :yaml)
push_frontend_feature_flag(:labels_widget, @project, default_enabled: :yaml)
......
......@@ -80,7 +80,7 @@ module Issues
todo_service.reassigned_assignable(issue, current_user, old_assignees)
track_incident_action(current_user, issue, :incident_assigned)
if Gitlab::ActionCable::Config.in_app? || Feature.enabled?(:broadcast_issue_updates, issue.project)
if Feature.enabled?(:broadcast_issue_updates, issue.project, default_enabled: :yaml)
GraphqlTriggers.issuable_assignees_updated(issue)
end
end
......
......@@ -59,8 +59,4 @@ Rails.application.configure do
config.logger = ActiveSupport::TaggedLogging.new(Logger.new(nil))
config.log_level = :fatal
end
# Mount the ActionCable Engine in-app so that we don't have to spawn another Puma
# process for feature specs
ENV['ACTION_CABLE_IN_APP'] = 'true'
end
---
name: broadcast_issue_updates
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30732
rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/delivery/-/issues/1210
rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/production/-/issues/3413
milestone: '13.0'
type: development
group: group::project management
default_enabled: false
default_enabled: true
......@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/delivery/-/issues/1210
milestone: '13.0'
type: development
group: group::project management
default_enabled: false
default_enabled: true
......@@ -65,7 +65,7 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled?
Gitlab::Metrics::Samplers::DatabaseSampler.initialize_instance.start
Gitlab::Metrics::Samplers::ThreadsSampler.initialize_instance.start
if Gitlab::Runtime.action_cable?
if Gitlab::Runtime.web_server?
Gitlab::Metrics::Samplers::ActionCableSampler.instance.start
end
......
......@@ -3,8 +3,7 @@
require 'action_cable/subscription_adapter/redis'
Rails.application.configure do
# Mount the ActionCable engine when in-app mode is enabled
config.action_cable.mount_path = Gitlab::ActionCable::Config.in_app? ? '/-/cable' : nil
config.action_cable.mount_path = '/-/cable'
config.action_cable.url = Gitlab::Utils.append_path(Gitlab.config.gitlab.relative_url_root, '/-/cable')
config.action_cable.worker_pool_size = Gitlab::ActionCable::Config.worker_pool_size
......
......@@ -380,12 +380,18 @@ You can also use the `/iteration`
[quick action](../quick_actions.md#issues-merge-requests-and-epics)
in a comment or description field.
## Real-time sidebar **(FREE SELF)**
## Real-time sidebar
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17589) in GitLab 13.3.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17589) in GitLab 13.3. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/3413) in GitLab 13.9.
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/17589) in GitLab 14.5.
Assignees in the sidebar are updated in real time. This feature is **disabled by default**.
To enable it, you need to enable [Action Cable in-app mode](https://docs.gitlab.com/omnibus/settings/actioncable.html).
FLAG:
On self-managed GitLab, by default this feature is available. To hide the feature per project or for your entire instance, ask an administrator to
[disable the feature flags](../../../administration/feature_flags.md) named `real_time_issue_sidebar` and `broadcast_issue_updates`.
On GitLab.com, this feature is available.
Assignees in the sidebar are updated in real time.
## Similar issues
......
......@@ -4,10 +4,6 @@ module Gitlab
module ActionCable
class Config
class << self
def in_app?
Gitlab::Utils.to_boolean(ENV.fetch('ACTION_CABLE_IN_APP', false))
end
def worker_pool_size
ENV.fetch('ACTION_CABLE_WORKER_POOL_SIZE', 4).to_i
end
......
......@@ -39,23 +39,14 @@ module Gitlab
def sample
pool = @action_cable.worker_pool.executor
labels = {
server_mode: server_mode
}
metrics[:active_connections].set(labels, @action_cable.connections.size)
metrics[:pool_min_size].set(labels, pool.min_length)
metrics[:pool_max_size].set(labels, pool.max_length)
metrics[:pool_current_size].set(labels, pool.length)
metrics[:pool_largest_size].set(labels, pool.largest_length)
metrics[:pool_completed_tasks].set(labels, pool.completed_task_count)
metrics[:pool_pending_tasks].set(labels, pool.queue_length)
end
private
def server_mode
Gitlab::ActionCable::Config.in_app? ? 'in-app' : 'standalone'
metrics[:active_connections].set({}, @action_cable.connections.size)
metrics[:pool_min_size].set({}, pool.min_length)
metrics[:pool_max_size].set({}, pool.max_length)
metrics[:pool_current_size].set({}, pool.length)
metrics[:pool_largest_size].set({}, pool.largest_length)
metrics[:pool_completed_tasks].set({}, pool.completed_task_count)
metrics[:pool_pending_tasks].set({}, pool.queue_length)
end
end
end
......
......@@ -63,12 +63,8 @@ module Gitlab
puma?
end
def action_cable?
web_server? && (!!defined?(ACTION_CABLE_SERVER) || Gitlab::ActionCable::Config.in_app?)
end
def multi_threaded?
puma? || sidekiq? || action_cable?
puma? || sidekiq?
end
def puma_in_clustered_mode?
......@@ -92,7 +88,7 @@ module Gitlab
threads += Sidekiq.options[:concurrency] + 2
end
if action_cable?
if web_server?
threads += Gitlab::ActionCable::Config.worker_pool_size
end
......
......@@ -1084,28 +1084,30 @@ RSpec.describe Projects::IssuesController do
end
context 'real-time sidebar feature flag' do
using RSpec::Parameterized::TableSyntax
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project) }
where(:action_cable_in_app_enabled, :feature_flag_enabled, :gon_feature_flag) do
true | true | true
true | false | true
false | true | true
false | false | false
context 'when enabled' do
before do
stub_feature_flags(real_time_issue_sidebar: true)
end
it 'pushes the correct value to the frontend' do
go(id: issue.to_param)
expect(Gon.features).to include('realTimeIssueSidebar' => true)
end
end
with_them do
context 'when disabled' do
before do
expect(Gitlab::ActionCable::Config).to receive(:in_app?).and_return(action_cable_in_app_enabled)
stub_feature_flags(real_time_issue_sidebar: feature_flag_enabled)
stub_feature_flags(real_time_issue_sidebar: false)
end
it 'broadcasts to the issues channel based on ActionCable and feature flag values' do
it 'pushes the correct value to the frontend' do
go(id: issue.to_param)
expect(Gon.features).to include('realTimeIssueSidebar' => gon_feature_flag)
expect(Gon.features).to include('realTimeIssueSidebar' => false)
end
end
end
......
......@@ -23,64 +23,46 @@ RSpec.describe Gitlab::Metrics::Samplers::ActionCableSampler do
allow(pool).to receive(:queue_length).and_return(6)
end
shared_examples 'collects metrics' do |expected_labels|
it 'includes active connections' do
expect(subject.metrics[:active_connections]).to receive(:set).with(expected_labels, 0)
it 'includes active connections' do
expect(subject.metrics[:active_connections]).to receive(:set).with({}, 0)
subject.sample
end
it 'includes minimum worker pool size' do
expect(subject.metrics[:pool_min_size]).to receive(:set).with(expected_labels, 1)
subject.sample
end
it 'includes maximum worker pool size' do
expect(subject.metrics[:pool_max_size]).to receive(:set).with(expected_labels, 2)
subject.sample
end
subject.sample
end
it 'includes current worker pool size' do
expect(subject.metrics[:pool_current_size]).to receive(:set).with(expected_labels, 3)
it 'includes minimum worker pool size' do
expect(subject.metrics[:pool_min_size]).to receive(:set).with({}, 1)
subject.sample
end
subject.sample
end
it 'includes largest worker pool size' do
expect(subject.metrics[:pool_largest_size]).to receive(:set).with(expected_labels, 4)
it 'includes maximum worker pool size' do
expect(subject.metrics[:pool_max_size]).to receive(:set).with({}, 2)
subject.sample
end
subject.sample
end
it 'includes worker pool completed task count' do
expect(subject.metrics[:pool_completed_tasks]).to receive(:set).with(expected_labels, 5)
it 'includes current worker pool size' do
expect(subject.metrics[:pool_current_size]).to receive(:set).with({}, 3)
subject.sample
end
subject.sample
end
it 'includes worker pool pending task count' do
expect(subject.metrics[:pool_pending_tasks]).to receive(:set).with(expected_labels, 6)
it 'includes largest worker pool size' do
expect(subject.metrics[:pool_largest_size]).to receive(:set).with({}, 4)
subject.sample
end
subject.sample
end
context 'for in-app mode' do
before do
expect(Gitlab::ActionCable::Config).to receive(:in_app?).and_return(true)
end
it 'includes worker pool completed task count' do
expect(subject.metrics[:pool_completed_tasks]).to receive(:set).with({}, 5)
it_behaves_like 'collects metrics', server_mode: 'in-app'
subject.sample
end
context 'for standalone mode' do
before do
expect(Gitlab::ActionCable::Config).to receive(:in_app?).and_return(false)
end
it 'includes worker pool pending task count' do
expect(subject.metrics[:pool_pending_tasks]).to receive(:set).with({}, 6)
it_behaves_like 'collects metrics', server_mode: 'standalone'
subject.sample
end
end
end
......@@ -48,10 +48,9 @@ RSpec.describe Gitlab::Runtime do
before do
stub_const('::Puma', puma_type)
stub_env('ACTION_CABLE_IN_APP', 'false')
end
it_behaves_like "valid runtime", :puma, 1
it_behaves_like "valid runtime", :puma, 1 + Gitlab::ActionCable::Config.worker_pool_size
end
context "puma with cli_config" do
......@@ -61,27 +60,16 @@ RSpec.describe Gitlab::Runtime do
before do
stub_const('::Puma', puma_type)
allow(puma_type).to receive_message_chain(:cli_config, :options).and_return(max_threads: 2, workers: max_workers)
stub_env('ACTION_CABLE_IN_APP', 'false')
end
it_behaves_like "valid runtime", :puma, 3
it_behaves_like "valid runtime", :puma, 3 + Gitlab::ActionCable::Config.worker_pool_size
context "when ActionCable in-app mode is enabled" do
context "when ActionCable worker pool size is configured" do
before do
stub_env('ACTION_CABLE_IN_APP', 'true')
stub_env('ACTION_CABLE_WORKER_POOL_SIZE', '3')
stub_env('ACTION_CABLE_WORKER_POOL_SIZE', 10)
end
it_behaves_like "valid runtime", :puma, 6
end
context "when ActionCable standalone is run" do
before do
stub_const('ACTION_CABLE_SERVER', true)
stub_env('ACTION_CABLE_WORKER_POOL_SIZE', '8')
end
it_behaves_like "valid runtime", :puma, 11
it_behaves_like "valid runtime", :puma, 13
end
describe ".puma_in_clustered_mode?" do
......
......@@ -1248,28 +1248,38 @@ RSpec.describe Issues::UpdateService, :mailer do
let(:closed_issuable) { create(:closed_issue, project: project) }
end
context 'real-time updates' do
using RSpec::Parameterized::TableSyntax
context 'broadcasting issue assignee updates' do
let(:update_params) { { assignee_ids: [user2.id] } }
where(:action_cable_in_app_enabled, :feature_flag_enabled, :should_broadcast) do
true | true | true
true | false | true
false | true | true
false | false | false
end
context 'when feature flag is enabled' do
before do
stub_feature_flags(broadcast_issue_updates: true)
end
it 'triggers the GraphQL subscription' do
expect(GraphqlTriggers).to receive(:issuable_assignees_updated).with(issue)
update_issue(update_params)
end
with_them do
it 'broadcasts to the issues channel based on ActionCable and feature flag values' do
allow(Gitlab::ActionCable::Config).to receive(:in_app?).and_return(action_cable_in_app_enabled)
stub_feature_flags(broadcast_issue_updates: feature_flag_enabled)
context 'when assignee is not updated' do
let(:update_params) { { title: 'Some other title' } }
if should_broadcast
expect(GraphqlTriggers).to receive(:issuable_assignees_updated).with(issue)
else
it 'does not trigger the GraphQL subscription' do
expect(GraphqlTriggers).not_to receive(:issuable_assignees_updated).with(issue)
update_issue(update_params)
end
end
end
context 'when feature flag is disabled' do
before do
stub_feature_flags(broadcast_issue_updates: false)
end
it 'does not trigger the GraphQL subscription' do
expect(GraphqlTriggers).not_to receive(:issuable_assignees_updated).with(issue)
update_issue(update_params)
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