diff --git a/bin/sidekiq-cluster b/bin/sidekiq-cluster index 47f8e82d2283..db7833acdc91 100755 --- a/bin/sidekiq-cluster +++ b/bin/sidekiq-cluster @@ -1,13 +1,7 @@ #!/usr/bin/env ruby # frozen_string_literal: true -require 'optparse' -require_relative '../lib/gitlab' -require_relative '../lib/gitlab/utils' -require_relative '../lib/gitlab/sidekiq_config/cli_methods' -require_relative '../lib/gitlab/sidekiq_config/worker_matcher' -require_relative '../lib/gitlab/sidekiq_cluster' -require_relative '../lib/gitlab/sidekiq_cluster/cli' +require_relative '../sidekiq_cluster/cli' Thread.abort_on_exception = true diff --git a/lib/gitlab/sidekiq_cluster/cli.rb b/sidekiq_cluster/cli.rb similarity index 92% rename from lib/gitlab/sidekiq_cluster/cli.rb rename to sidekiq_cluster/cli.rb index 3dee257229d9..55b4521d37d4 100644 --- a/lib/gitlab/sidekiq_cluster/cli.rb +++ b/sidekiq_cluster/cli.rb @@ -4,27 +4,21 @@ require 'logger' require 'time' +# In environments where code is preloaded and cached such as `spring`, +# we may run into "already initialized" warnings, hence the check. +require_relative '../lib/gitlab' unless Object.const_defined?('Gitlab') +require_relative '../lib/gitlab/utils' +require_relative '../lib/gitlab/sidekiq_config/cli_methods' +require_relative '../lib/gitlab/sidekiq_config/worker_matcher' +require_relative '../lib/gitlab/sidekiq_logging/json_formatter' +require_relative 'sidekiq_cluster' + module Gitlab module SidekiqCluster class CLI - CHECK_TERMINATE_INTERVAL_SECONDS = 1 - - # How long to wait when asking for a clean termination. - # It maps the Sidekiq default timeout: - # https://github.com/mperham/sidekiq/wiki/Signals#term - # - # This value is passed to Sidekiq's `-t` if none - # is given through arguments. - DEFAULT_SOFT_TIMEOUT_SECONDS = 25 - - # After surpassing the soft timeout. - DEFAULT_HARD_TIMEOUT_SECONDS = 5 - CommandError = Class.new(StandardError) def initialize(log_output = $stderr) - require_relative '../../../lib/gitlab/sidekiq_logging/json_formatter' - # As recommended by https://github.com/mperham/sidekiq/wiki/Advanced-Options#concurrency @max_concurrency = 50 @min_concurrency = 0 diff --git a/sidekiq_cluster/dependencies.rb b/sidekiq_cluster/dependencies.rb new file mode 100644 index 000000000000..91e91475f159 --- /dev/null +++ b/sidekiq_cluster/dependencies.rb @@ -0,0 +1,6 @@ +# rubocop:disable Naming/FileName +# frozen_string_literal: true + +require 'shellwords' + +# rubocop:enable Naming/FileName diff --git a/lib/gitlab/sidekiq_cluster.rb b/sidekiq_cluster/sidekiq_cluster.rb similarity index 89% rename from lib/gitlab/sidekiq_cluster.rb rename to sidekiq_cluster/sidekiq_cluster.rb index cc1bd282da87..49478ba740dd 100644 --- a/lib/gitlab/sidekiq_cluster.rb +++ b/sidekiq_cluster/sidekiq_cluster.rb @@ -1,9 +1,22 @@ # frozen_string_literal: true -require 'shellwords' +require_relative 'dependencies' module Gitlab module SidekiqCluster + CHECK_TERMINATE_INTERVAL_SECONDS = 1 + + # How long to wait when asking for a clean termination. + # It maps the Sidekiq default timeout: + # https://github.com/mperham/sidekiq/wiki/Signals#term + # + # This value is passed to Sidekiq's `-t` if none + # is given through arguments. + DEFAULT_SOFT_TIMEOUT_SECONDS = 25 + + # After surpassing the soft timeout. + DEFAULT_HARD_TIMEOUT_SECONDS = 5 + # The signals that should terminate both the master and workers. TERMINATE_SIGNALS = %i(INT TERM).freeze @@ -62,7 +75,7 @@ def self.signal_processes(pids, signal) # directory - The directory of the Rails application. # # Returns an Array containing the PIDs of the started processes. - def self.start(queues, env: :development, directory: Dir.pwd, max_concurrency: 50, min_concurrency: 0, timeout: CLI::DEFAULT_SOFT_TIMEOUT_SECONDS, dryrun: false) + def self.start(queues, env: :development, directory: Dir.pwd, max_concurrency: 50, min_concurrency: 0, timeout: DEFAULT_SOFT_TIMEOUT_SECONDS, dryrun: false) queues.map.with_index do |pair, index| start_sidekiq(pair, env: env, directory: directory, diff --git a/spec/lib/gitlab/sidekiq_cluster/cli_spec.rb b/spec/commands/sidekiq_cluster/cli_spec.rb similarity index 96% rename from spec/lib/gitlab/sidekiq_cluster/cli_spec.rb rename to spec/commands/sidekiq_cluster/cli_spec.rb index e818b03cf759..baa4a2b4ec3e 100644 --- a/spec/lib/gitlab/sidekiq_cluster/cli_spec.rb +++ b/spec/commands/sidekiq_cluster/cli_spec.rb @@ -3,9 +3,11 @@ require 'fast_spec_helper' require 'rspec-parameterized' -RSpec.describe Gitlab::SidekiqCluster::CLI do +require_relative '../../../sidekiq_cluster/cli' + +RSpec.describe Gitlab::SidekiqCluster::CLI do # rubocop:disable RSpec/FilePath let(:cli) { described_class.new('/dev/null') } - let(:timeout) { described_class::DEFAULT_SOFT_TIMEOUT_SECONDS } + let(:timeout) { Gitlab::SidekiqCluster::DEFAULT_SOFT_TIMEOUT_SECONDS } let(:default_options) do { env: 'test', directory: Dir.pwd, max_concurrency: 50, min_concurrency: 0, dryrun: false, timeout: timeout } end @@ -103,7 +105,7 @@ it 'when not given', 'starts Sidekiq workers with default timeout' do expect(Gitlab::SidekiqCluster).to receive(:start) - .with([['foo']], default_options.merge(timeout: described_class::DEFAULT_SOFT_TIMEOUT_SECONDS)) + .with([['foo']], default_options.merge(timeout: Gitlab::SidekiqCluster::DEFAULT_SOFT_TIMEOUT_SECONDS)) cli.run(%w(foo)) end @@ -271,7 +273,7 @@ expect(Gitlab::SidekiqCluster).to receive(:signal_processes) .with([], "-KILL") - stub_const("Gitlab::SidekiqCluster::CLI::CHECK_TERMINATE_INTERVAL_SECONDS", 0.1) + stub_const("Gitlab::SidekiqCluster::CHECK_TERMINATE_INTERVAL_SECONDS", 0.1) allow(cli).to receive(:terminate_timeout_seconds) { 1 } cli.wait_for_termination @@ -301,7 +303,7 @@ cli.run(%w(foo)) - stub_const("Gitlab::SidekiqCluster::CLI::CHECK_TERMINATE_INTERVAL_SECONDS", 0.1) + stub_const("Gitlab::SidekiqCluster::CHECK_TERMINATE_INTERVAL_SECONDS", 0.1) allow(cli).to receive(:terminate_timeout_seconds) { 1 } cli.wait_for_termination diff --git a/spec/lib/gitlab/sidekiq_cluster_spec.rb b/spec/sidekiq_cluster/sidekiq_cluster_spec.rb similarity index 98% rename from spec/lib/gitlab/sidekiq_cluster_spec.rb rename to spec/sidekiq_cluster/sidekiq_cluster_spec.rb index 3c6ea054968b..1d2b47e78cee 100644 --- a/spec/lib/gitlab/sidekiq_cluster_spec.rb +++ b/spec/sidekiq_cluster/sidekiq_cluster_spec.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true -require 'fast_spec_helper' require 'rspec-parameterized' -RSpec.describe Gitlab::SidekiqCluster do +require_relative '../../sidekiq_cluster/sidekiq_cluster' + +RSpec.describe Gitlab::SidekiqCluster do # rubocop:disable RSpec/FilePath describe '.trap_signals' do it 'traps the given signals' do expect(described_class).to receive(:trap).ordered.with(:INT) diff --git a/spec/tooling/quality/test_level_spec.rb b/spec/tooling/quality/test_level_spec.rb index 40eb93c838b3..94fa9d682e15 100644 --- a/spec/tooling/quality/test_level_spec.rb +++ b/spec/tooling/quality/test_level_spec.rb @@ -49,7 +49,7 @@ context 'when level is integration' do it 'returns a pattern' do expect(subject.pattern(:integration)) - .to eq("spec/{controllers,mailers,requests}{,/**/}*_spec.rb") + .to eq("spec/{commands,controllers,mailers,requests}{,/**/}*_spec.rb") end end @@ -131,7 +131,7 @@ context 'when level is integration' do it 'returns a regexp' do expect(subject.regexp(:integration)) - .to eq(%r{spec/(controllers|mailers|requests)}) + .to eq(%r{spec/(commands|controllers|mailers|requests)}) end end @@ -204,6 +204,10 @@ expect(subject.level_for('spec/mailers/abuse_report_mailer_spec.rb')).to eq(:integration) end + it 'returns the correct level for an integration test in a subfolder' do + expect(subject.level_for('spec/commands/sidekiq_cluster/cli.rb')).to eq(:integration) + end + it 'returns the correct level for a system test' do expect(subject.level_for('spec/features/abuse_report_spec.rb')).to eq(:system) end diff --git a/tooling/quality/test_level.rb b/tooling/quality/test_level.rb index 57eb19517ea1..5fbaad073c0a 100644 --- a/tooling/quality/test_level.rb +++ b/tooling/quality/test_level.rb @@ -54,6 +54,7 @@ class TestLevel tooling ], integration: %w[ + commands controllers mailers requests