Commit cf9a27f0 authored by Sean McGivern's avatar Sean McGivern

Use surrounding context's feature category for unowned workers

When we're in Sidekiq, in most cases we want to use the feature category
of the current worker class in logs and metrics. If a worker with the
'users' feature category is called by an endpoint that has the
'issue tracking' feature category, then 'users' is the more specific
category.

However, for workers without an owning feature category, this is worse:
we're effectively throwing away the information from the surrounding
context to give the least-specific information we could possibly give.
This changes that so that in logs and in metrics, we'll use the feature
category from the calling context for workers that don't have an owner.
parent 8875871d
...@@ -1881,7 +1881,7 @@ ...@@ -1881,7 +1881,7 @@
:tags: [] :tags: []
- :name: default - :name: default
:worker_name: :worker_name:
:feature_category: :feature_category: :not_owned
:has_external_dependencies: :has_external_dependencies:
:urgency: :urgency:
:resource_boundary: :resource_boundary:
...@@ -2206,7 +2206,7 @@ ...@@ -2206,7 +2206,7 @@
:tags: [] :tags: []
- :name: mailers - :name: mailers
:worker_name: ActionMailer::MailDeliveryJob :worker_name: ActionMailer::MailDeliveryJob
:feature_category: :issue_tracking :feature_category: :not_owned
:has_external_dependencies: :has_external_dependencies:
:urgency: low :urgency: low
:resource_boundary: :resource_boundary:
......
...@@ -46,8 +46,14 @@ module WorkerAttributes ...@@ -46,8 +46,14 @@ module WorkerAttributes
set_class_attribute(:feature_category, :not_owned) set_class_attribute(:feature_category, :not_owned)
end end
# Special case: if a worker is not owned, get the feature category
# (if present) from the calling context.
def get_feature_category def get_feature_category
get_class_attribute(:feature_category) feature_category = get_class_attribute(:feature_category)
return feature_category unless feature_category == :not_owned
Gitlab::ApplicationContext.current_context_attribute('meta.feature_category') || feature_category
end end
def feature_category_not_owned? def feature_category_not_owned?
......
...@@ -72,6 +72,11 @@ class SomeCrossCuttingConcernWorker ...@@ -72,6 +72,11 @@ class SomeCrossCuttingConcernWorker
end end
``` ```
Workers marked as not owned workers will, when possible, use the
category of their caller (worker or HTTP endpoint) in metrics and logs.
For instance, `ReactiveCachingWorker` can have multiple feature
categories in metrics and logs.
## Rails controllers ## Rails controllers
Specifying feature categories on controller actions can be done using Specifying feature categories on controller actions can be done using
......
...@@ -27,6 +27,10 @@ RSpec.describe Elastic::IndexingControlService, :clean_gitlab_redis_shared_state ...@@ -27,6 +27,10 @@ RSpec.describe Elastic::IndexingControlService, :clean_gitlab_redis_shared_state
subject { described_class.new(worker_class) } subject { described_class.new(worker_class) }
before do
stub_const(worker_class.name, worker_class)
end
describe '.initialize' do describe '.initialize' do
it 'raises an exception when passed wrong worker' do it 'raises an exception when passed wrong worker' do
expect { described_class.new(Class.new) }.to raise_error(ArgumentError) expect { described_class.new(Class.new) }.to raise_error(ArgumentError)
...@@ -154,6 +158,10 @@ RSpec.describe Elastic::IndexingControlService, :clean_gitlab_redis_shared_state ...@@ -154,6 +158,10 @@ RSpec.describe Elastic::IndexingControlService, :clean_gitlab_redis_shared_state
let(:other_subject) { described_class.new(second_worker_class) } let(:other_subject) { described_class.new(second_worker_class) }
before do
stub_const(second_worker_class.name, second_worker_class)
end
it 'allows to use queues independently of each other' do it 'allows to use queues independently of each other' do
expect { subject.add_to_waiting_queue!(worker_args, worker_context) }.to change { subject.queue_size }.from(0).to(1) expect { subject.add_to_waiting_queue!(worker_args, worker_context) }.to change { subject.queue_size }.from(0).to(1)
......
...@@ -23,12 +23,12 @@ module Gitlab ...@@ -23,12 +23,12 @@ module Gitlab
DEFAULT_WORKERS = { DEFAULT_WORKERS = {
'_' => DummyWorker.new( '_' => DummyWorker.new(
queue: 'default', queue: 'default',
weight: 1, tags: [] weight: 1,
tags: []
), ),
'ActionMailer::MailDeliveryJob' => DummyWorker.new( 'ActionMailer::MailDeliveryJob' => DummyWorker.new(
name: 'ActionMailer::MailDeliveryJob', name: 'ActionMailer::MailDeliveryJob',
queue: 'mailers', queue: 'mailers',
feature_category: :issue_tracking,
urgency: 'low', urgency: 'low',
weight: 2, weight: 2,
tags: [] tags: []
......
...@@ -6,7 +6,6 @@ module Gitlab ...@@ -6,7 +6,6 @@ module Gitlab
class DummyWorker class DummyWorker
ATTRIBUTE_METHODS = { ATTRIBUTE_METHODS = {
name: :name, name: :name,
feature_category: :get_feature_category,
has_external_dependencies: :worker_has_external_dependencies?, has_external_dependencies: :worker_has_external_dependencies?,
urgency: :get_urgency, urgency: :get_urgency,
resource_boundary: :get_worker_resource_boundary, resource_boundary: :get_worker_resource_boundary,
...@@ -27,6 +26,20 @@ module Gitlab ...@@ -27,6 +26,20 @@ module Gitlab
nil nil
end end
# All dummy workers are unowned; get the feature category from the
# context if available.
def get_feature_category
Gitlab::ApplicationContext.current_context_attribute('meta.feature_category') || :not_owned
end
def get_worker_context
nil
end
def context_for_arguments(*)
nil
end
ATTRIBUTE_METHODS.each do |attribute, meth| ATTRIBUTE_METHODS.each do |attribute, meth|
define_method meth do define_method meth do
@attributes[attribute] @attributes[attribute]
......
...@@ -13,6 +13,13 @@ module Gitlab ...@@ -13,6 +13,13 @@ module Gitlab
chain.add ::Gitlab::SidekiqMiddleware::SizeLimiter::Server chain.add ::Gitlab::SidekiqMiddleware::SizeLimiter::Server
chain.add ::Gitlab::SidekiqMiddleware::Monitor chain.add ::Gitlab::SidekiqMiddleware::Monitor
# Labkit wraps the job in the `Labkit::Context` resurrected from
# the job-hash. We need properties from the context for
# recording metrics, so this needs to be before
# `::Gitlab::SidekiqMiddleware::ServerMetrics` (if we're using
# that).
chain.add ::Labkit::Middleware::Sidekiq::Server
if metrics if metrics
chain.add ::Gitlab::SidekiqMiddleware::ServerMetrics chain.add ::Gitlab::SidekiqMiddleware::ServerMetrics
...@@ -24,7 +31,6 @@ module Gitlab ...@@ -24,7 +31,6 @@ module Gitlab
chain.add ::Gitlab::SidekiqMiddleware::RequestStoreMiddleware chain.add ::Gitlab::SidekiqMiddleware::RequestStoreMiddleware
chain.add ::Gitlab::SidekiqMiddleware::ExtraDoneLogMetadata chain.add ::Gitlab::SidekiqMiddleware::ExtraDoneLogMetadata
chain.add ::Gitlab::SidekiqMiddleware::BatchLoader chain.add ::Gitlab::SidekiqMiddleware::BatchLoader
chain.add ::Labkit::Middleware::Sidekiq::Server
chain.add ::Gitlab::SidekiqMiddleware::InstrumentationLogger chain.add ::Gitlab::SidekiqMiddleware::InstrumentationLogger
chain.add ::Gitlab::SidekiqMiddleware::AdminMode::Server chain.add ::Gitlab::SidekiqMiddleware::AdminMode::Server
chain.add ::Gitlab::SidekiqVersioning::Middleware chain.add ::Gitlab::SidekiqVersioning::Middleware
......
...@@ -14,6 +14,7 @@ module Gitlab ...@@ -14,6 +14,7 @@ module Gitlab
def call(worker_class, job, queue, _redis_pool) def call(worker_class, job, queue, _redis_pool)
# worker_class can either be the string or class of the worker being enqueued. # worker_class can either be the string or class of the worker being enqueued.
worker_class = worker_class.safe_constantize if worker_class.respond_to?(:safe_constantize) worker_class = worker_class.safe_constantize if worker_class.respond_to?(:safe_constantize)
labels = create_labels(worker_class, queue, job) labels = create_labels(worker_class, queue, job)
labels[:scheduling] = job.key?('at') ? 'delayed' : 'immediate' labels[:scheduling] = job.key?('at') ? 'delayed' : 'immediate'
......
...@@ -3,14 +3,21 @@ ...@@ -3,14 +3,21 @@
module Gitlab module Gitlab
module SidekiqMiddleware module SidekiqMiddleware
module MetricsHelper module MetricsHelper
include ::Gitlab::SidekiqMiddleware::WorkerContext
TRUE_LABEL = "yes" TRUE_LABEL = "yes"
FALSE_LABEL = "no" FALSE_LABEL = "no"
private private
def create_labels(worker_class, queue, job) def create_labels(worker_class, queue, job)
worker_name = (job['wrapped'].presence || worker_class).to_s worker = find_worker(worker_class, job)
worker = find_worker(worker_name, worker_class)
# This should never happen: we should always be able to find a
# worker class for a given Sidekiq job. But if we can't, we
# shouldn't blow up here, because we want to record this in our
# metrics.
worker_name = worker.try(:name) || worker.class.name
labels = { queue: queue.to_s, labels = { queue: queue.to_s,
worker: worker_name, worker: worker_name,
...@@ -23,9 +30,7 @@ module Gitlab ...@@ -23,9 +30,7 @@ module Gitlab
labels[:urgency] = worker.get_urgency.to_s labels[:urgency] = worker.get_urgency.to_s
labels[:external_dependencies] = bool_as_label(worker.worker_has_external_dependencies?) labels[:external_dependencies] = bool_as_label(worker.worker_has_external_dependencies?)
labels[:feature_category] = worker.get_feature_category.to_s
feature_category = worker.get_feature_category
labels[:feature_category] = feature_category.to_s
resource_boundary = worker.get_worker_resource_boundary resource_boundary = worker.get_worker_resource_boundary
labels[:boundary] = resource_boundary == :unknown ? "" : resource_boundary.to_s labels[:boundary] = resource_boundary == :unknown ? "" : resource_boundary.to_s
...@@ -36,10 +41,6 @@ module Gitlab ...@@ -36,10 +41,6 @@ module Gitlab
def bool_as_label(value) def bool_as_label(value)
value ? TRUE_LABEL : FALSE_LABEL value ? TRUE_LABEL : FALSE_LABEL
end end
def find_worker(worker_name, worker_class)
Gitlab::SidekiqConfig::DEFAULT_WORKERS.fetch(worker_name, worker_class)
end
end end
end end
end end
...@@ -10,6 +10,12 @@ module Gitlab ...@@ -10,6 +10,12 @@ module Gitlab
context_or_nil.use(&block) context_or_nil.use(&block)
end end
def find_worker(worker_class, job)
worker_name = (job['wrapped'].presence || worker_class).to_s
Gitlab::SidekiqConfig::DEFAULT_WORKERS[worker_name]&.klass || worker_class
end
end end
end end
end end
...@@ -7,20 +7,15 @@ module Gitlab ...@@ -7,20 +7,15 @@ module Gitlab
include Gitlab::SidekiqMiddleware::WorkerContext include Gitlab::SidekiqMiddleware::WorkerContext
def call(worker_class_or_name, job, _queue, _redis_pool, &block) def call(worker_class_or_name, job, _queue, _redis_pool, &block)
worker_class = worker_class_or_name.to_s.safe_constantize worker_class = find_worker(worker_class_or_name.to_s.safe_constantize, job)
# Mailers can't be constantized like this # This is not a worker we know about, perhaps from a gem
return yield unless worker_class return yield unless worker_class
return yield unless worker_class.include?(::ApplicationWorker) return yield unless worker_class.respond_to?(:context_for_arguments)
context_for_args = worker_class.context_for_arguments(job['args']) context_for_args = worker_class.context_for_arguments(job['args'])
wrap_in_optional_context(context_for_args) do wrap_in_optional_context(context_for_args, &block)
# This should be inside the context for the arguments so
# that we don't override the feature category on the worker
# with the one from the caller.
Gitlab::ApplicationContext.with_context(feature_category: worker_class.get_feature_category.to_s, &block)
end
end end
end end
end end
......
...@@ -7,7 +7,7 @@ module Gitlab ...@@ -7,7 +7,7 @@ module Gitlab
include Gitlab::SidekiqMiddleware::WorkerContext include Gitlab::SidekiqMiddleware::WorkerContext
def call(worker, job, _queue, &block) def call(worker, job, _queue, &block)
worker_class = worker.class worker_class = find_worker(worker.class, job)
# This is not a worker we know about, perhaps from a gem # This is not a worker we know about, perhaps from a gem
return yield unless worker_class.respond_to?(:get_worker_context) return yield unless worker_class.respond_to?(:get_worker_context)
......
...@@ -1631,10 +1631,19 @@ RSpec.describe Gitlab::Database::MigrationHelpers do ...@@ -1631,10 +1631,19 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
let(:worker) do let(:worker) do
Class.new do Class.new do
include Sidekiq::Worker include Sidekiq::Worker
sidekiq_options queue: 'test' sidekiq_options queue: 'test'
def self.name
'WorkerClass'
end
end end
end end
before do
stub_const(worker.name, worker)
end
describe '#sidekiq_queue_length' do describe '#sidekiq_queue_length' do
context 'when queue is empty' do context 'when queue is empty' do
it 'returns zero' do it 'returns zero' do
......
...@@ -63,5 +63,18 @@ RSpec.describe Gitlab::SidekiqMiddleware::ClientMetrics do ...@@ -63,5 +63,18 @@ RSpec.describe Gitlab::SidekiqMiddleware::ClientMetrics do
Sidekiq::Testing.inline! { TestWorker.perform_in(1.second) } Sidekiq::Testing.inline! { TestWorker.perform_in(1.second) }
end end
end end
context 'when the worker class cannot be found' do
it 'increments enqueued jobs metric with the worker labels set to NilClass' do
test_anonymous_worker = Class.new(TestWorker)
expect(enqueued_jobs_metric).to receive(:increment).with(a_hash_including(worker: 'NilClass'), 1)
# Sidekiq won't be able to create an instance of this class
expect do
Sidekiq::Testing.inline! { test_anonymous_worker.perform_async }
end.to raise_error(NameError)
end
end
end end
end end
...@@ -211,6 +211,9 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do ...@@ -211,6 +211,9 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
end end
end end
include_context 'server metrics with mocked prometheus'
include_context 'server metrics call'
before do before do
stub_const('TestWorker', Class.new) stub_const('TestWorker', Class.new)
TestWorker.class_eval do TestWorker.class_eval do
...@@ -234,9 +237,6 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do ...@@ -234,9 +237,6 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
end end
end end
include_context 'server metrics with mocked prometheus'
include_context 'server metrics call'
shared_context 'worker declaring data consistency' do shared_context 'worker declaring data consistency' do
let(:worker_class) { LBTestWorker } let(:worker_class) { LBTestWorker }
...@@ -308,5 +308,67 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do ...@@ -308,5 +308,67 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
end end
end end
end end
context 'feature attribution' do
let(:test_worker) do
category = worker_category
Class.new do
include Sidekiq::Worker
include WorkerAttributes
if category
feature_category category
else
feature_category_not_owned!
end
def perform
end
end
end
let(:context_category) { 'continuous_integration' }
let(:job) { { 'meta.feature_category' => 'continuous_integration' } }
before do
stub_const('TestWorker', test_worker)
end
around do |example|
with_sidekiq_server_middleware do |chain|
Gitlab::SidekiqMiddleware.server_configurator(
metrics: true,
arguments_logger: false,
memory_killer: false
).call(chain)
Sidekiq::Testing.inline! { example.run }
end
end
include_context 'server metrics with mocked prometheus'
include_context 'server metrics call'
context 'when a worker has a feature category' do
let(:worker_category) { 'authentication_and_authorization' }
it 'uses that category for metrics' do
expect(completion_seconds_metric).to receive(:observe).with(a_hash_including(feature_category: worker_category), anything)
TestWorker.process_job(job)
end
end
context 'when a worker does not have a feature category' do
let(:worker_category) { nil }
it 'uses the category from the context for metrics' do
expect(completion_seconds_metric).to receive(:observe).with(a_hash_including(feature_category: context_category), anything)
TestWorker.process_job(job)
end
end
end
end end
# rubocop: enable RSpec/MultipleMemoizedHelpers # rubocop: enable RSpec/MultipleMemoizedHelpers
...@@ -11,8 +11,6 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do ...@@ -11,8 +11,6 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
include ApplicationWorker include ApplicationWorker
feature_category :issue_tracking
def self.job_for_args(args) def self.job_for_args(args)
jobs.find { |job| job['args'] == args } jobs.find { |job| job['args'] == args }
end end
...@@ -23,7 +21,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do ...@@ -23,7 +21,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
end end
before do before do
stub_const('TestWithContextWorker', worker_class) stub_const(worker_class.name, worker_class)
end end
describe "#call" do describe "#call" do
...@@ -43,39 +41,5 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do ...@@ -43,39 +41,5 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
expect(job1['meta.user']).to eq(user_per_job['job1'].username) expect(job1['meta.user']).to eq(user_per_job['job1'].username)
expect(job2['meta.user']).to eq(user_per_job['job2'].username) expect(job2['meta.user']).to eq(user_per_job['job2'].username)
end end
context 'when the feature category is set in the context_proc' do
it 'takes the feature category from the worker, not the caller' do
TestWithContextWorker.bulk_perform_async_with_contexts(
%w(job1 job2),
arguments_proc: -> (name) { [name, 1, 2, 3] },
context_proc: -> (_) { { feature_category: 'code_review' } }
)
job1 = TestWithContextWorker.job_for_args(['job1', 1, 2, 3])
job2 = TestWithContextWorker.job_for_args(['job2', 1, 2, 3])
expect(job1['meta.feature_category']).to eq('issue_tracking')
expect(job2['meta.feature_category']).to eq('issue_tracking')
end
end
context 'when the feature category is already set in the surrounding block' do
it 'takes the feature category from the worker, not the caller' do
Gitlab::ApplicationContext.with_context(feature_category: 'authentication_and_authorization') do
TestWithContextWorker.bulk_perform_async_with_contexts(
%w(job1 job2),
arguments_proc: -> (name) { [name, 1, 2, 3] },
context_proc: -> (_) { {} }
)
end
job1 = TestWithContextWorker.job_for_args(['job1', 1, 2, 3])
job2 = TestWithContextWorker.job_for_args(['job2', 1, 2, 3])
expect(job1['meta.feature_category']).to eq('issue_tracking')
expect(job2['meta.feature_category']).to eq('issue_tracking')
end
end
end end
end end
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do
let(:worker_class) do let(:test_worker) do
Class.new do Class.new do
def self.name def self.name
"TestWorker" "TestWorker"
...@@ -23,6 +23,16 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do ...@@ -23,6 +23,16 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do
end end
end end
let(:not_owned_worker) do
Class.new(test_worker) do
def self.name
"NotOwnedWorker"
end
feature_category_not_owned!
end
end
let(:other_worker) do let(:other_worker) do
Class.new do Class.new do
def self.name def self.name
...@@ -37,7 +47,8 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do ...@@ -37,7 +47,8 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do
end end
before do before do
stub_const("TestWorker", worker_class) stub_const("TestWorker", test_worker)
stub_const("NotOwnedWorker", not_owned_worker)
stub_const("OtherWorker", other_worker) stub_const("OtherWorker", other_worker)
end end
...@@ -57,10 +68,24 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do ...@@ -57,10 +68,24 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do
expect(TestWorker.contexts['identifier'].keys).not_to include('meta.user') expect(TestWorker.contexts['identifier'].keys).not_to include('meta.user')
end end
it 'takes the feature category from the worker' do context 'feature category' do
TestWorker.perform_async('identifier', 1) it 'takes the feature category from the worker' do
Gitlab::ApplicationContext.with_context(feature_category: 'authentication_and_authorization') do
TestWorker.perform_async('identifier', 1)
end
expect(TestWorker.contexts['identifier']).to include('meta.feature_category' => 'foo')
end
expect(TestWorker.contexts['identifier']).to include('meta.feature_category' => 'foo') context 'when the worker is not owned' do
it 'takes the feature category from the surrounding context' do
Gitlab::ApplicationContext.with_context(feature_category: 'authentication_and_authorization') do
NotOwnedWorker.perform_async('identifier', 1)
end
expect(NotOwnedWorker.contexts['identifier']).to include('meta.feature_category' => 'authentication_and_authorization')
end
end
end end
it "doesn't fail for unknown workers" do it "doesn't fail for unknown workers" do
......
...@@ -58,13 +58,13 @@ RSpec.describe Gitlab::SidekiqMiddleware do ...@@ -58,13 +58,13 @@ RSpec.describe Gitlab::SidekiqMiddleware do
let(:all_sidekiq_middlewares) do let(:all_sidekiq_middlewares) do
[ [
::Gitlab::SidekiqMiddleware::Monitor, ::Gitlab::SidekiqMiddleware::Monitor,
::Labkit::Middleware::Sidekiq::Server,
::Gitlab::SidekiqMiddleware::ServerMetrics, ::Gitlab::SidekiqMiddleware::ServerMetrics,
::Gitlab::SidekiqMiddleware::ArgumentsLogger, ::Gitlab::SidekiqMiddleware::ArgumentsLogger,
::Gitlab::SidekiqMiddleware::MemoryKiller, ::Gitlab::SidekiqMiddleware::MemoryKiller,
::Gitlab::SidekiqMiddleware::RequestStoreMiddleware, ::Gitlab::SidekiqMiddleware::RequestStoreMiddleware,
::Gitlab::SidekiqMiddleware::ExtraDoneLogMetadata, ::Gitlab::SidekiqMiddleware::ExtraDoneLogMetadata,
::Gitlab::SidekiqMiddleware::BatchLoader, ::Gitlab::SidekiqMiddleware::BatchLoader,
::Labkit::Middleware::Sidekiq::Server,
::Gitlab::SidekiqMiddleware::InstrumentationLogger, ::Gitlab::SidekiqMiddleware::InstrumentationLogger,
::Gitlab::SidekiqMiddleware::AdminMode::Server, ::Gitlab::SidekiqMiddleware::AdminMode::Server,
::Gitlab::SidekiqVersioning::Middleware, ::Gitlab::SidekiqVersioning::Middleware,
......
...@@ -17,6 +17,9 @@ RSpec.shared_context 'server metrics with mocked prometheus' do ...@@ -17,6 +17,9 @@ RSpec.shared_context 'server metrics with mocked prometheus' do
let(:elasticsearch_requests_total) { double('elasticsearch calls total metric') } let(:elasticsearch_requests_total) { double('elasticsearch calls total metric') }
before do before do
allow(Gitlab::Metrics).to receive(:histogram).and_call_original
allow(Gitlab::Metrics).to receive(:counter).and_call_original
allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_queue_duration_seconds, anything, anything, anything).and_return(queue_duration_seconds) allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_queue_duration_seconds, anything, anything, anything).and_return(queue_duration_seconds)
allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_completion_seconds, anything, anything, anything).and_return(completion_seconds_metric) allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_completion_seconds, anything, anything, anything).and_return(completion_seconds_metric)
allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_cpu_seconds, anything, anything, anything).and_return(user_execution_seconds_metric) allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_cpu_seconds, anything, anything, anything).and_return(user_execution_seconds_metric)
......
...@@ -248,6 +248,10 @@ RSpec.describe ApplicationWorker do ...@@ -248,6 +248,10 @@ RSpec.describe ApplicationWorker do
end end
describe '.perform_async' do describe '.perform_async' do
before do
stub_const(worker.name, worker)
end
shared_examples_for 'worker utilizes load balancing capabilities' do |data_consistency| shared_examples_for 'worker utilizes load balancing capabilities' do |data_consistency|
before do before do
worker.data_consistency(data_consistency) worker.data_consistency(data_consistency)
...@@ -282,6 +286,10 @@ RSpec.describe ApplicationWorker do ...@@ -282,6 +286,10 @@ RSpec.describe ApplicationWorker do
end end
describe '.bulk_perform_async' do describe '.bulk_perform_async' do
before do
stub_const(worker.name, worker)
end
it 'enqueues jobs in bulk' do it 'enqueues jobs in bulk' do
Sidekiq::Testing.fake! do Sidekiq::Testing.fake! do
worker.bulk_perform_async([['Foo', [1]], ['Foo', [2]]]) worker.bulk_perform_async([['Foo', [1]], ['Foo', [2]]])
...@@ -293,6 +301,10 @@ RSpec.describe ApplicationWorker do ...@@ -293,6 +301,10 @@ RSpec.describe ApplicationWorker do
end end
describe '.bulk_perform_in' do describe '.bulk_perform_in' do
before do
stub_const(worker.name, worker)
end
context 'when delay is valid' do context 'when delay is valid' do
it 'correctly schedules jobs' do it 'correctly schedules jobs' do
Sidekiq::Testing.fake! do Sidekiq::Testing.fake! do
......
...@@ -13,6 +13,10 @@ RSpec.describe WorkerContext do ...@@ -13,6 +13,10 @@ RSpec.describe WorkerContext do
end end
end end
before do
stub_const(worker.name, worker)
end
describe '.worker_context' do describe '.worker_context' do
it 'allows modifying the context for the entire worker' do it 'allows modifying the context for the entire worker' do
worker.worker_context(user: build_stubbed(:user)) worker.worker_context(user: build_stubbed(:user))
......
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