Commit 294b5d42 authored by Sean McGivern's avatar Sean McGivern

Always use generated queue name for worker matching

When we match against workers, the `name` attribute is tricky. It means
the queue name, but which queue name?

1. The actual queue name (after applying worker routing rules)?
2. The generated queue name (based on the worker class name and queue
   namespace)?

Before this commit, it was 1, but that was confusing: it would start as
`default` (before the attribute was set), then change to the generated
queue name, then change again to the queue name based on worker routing
rules. Because the routing rules are evaluated on application load, this
was hard to debug and could give unexpected results.

Instead, we say that the `name` attribute always means item 2. This is
also the name present in `all_queues.yml`, and this file is referenced
in the documentation. That means it's more consistent and predictable,
and doesn't require changes to the router itself.
parent 6c1f9d85
...@@ -54,6 +54,10 @@ module ApplicationWorker ...@@ -54,6 +54,10 @@ module ApplicationWorker
subclass.after_set_class_attribute { subclass.set_queue } subclass.after_set_class_attribute { subclass.set_queue }
end end
def generated_queue_name
Gitlab::SidekiqConfig::WorkerRouter.queue_name_from_worker_name(self)
end
override :validate_worker_attributes! override :validate_worker_attributes!
def validate_worker_attributes! def validate_worker_attributes!
super super
......
...@@ -103,9 +103,11 @@ based on a subset of worker attributes: ...@@ -103,9 +103,11 @@ based on a subset of worker attributes:
- `worker_name` - the worker name. The other attributes are typically more useful as - `worker_name` - the worker name. The other attributes are typically more useful as
they are more general, but this is available in case a particular worker needs they are more general, but this is available in case a particular worker needs
to be selected. to be selected.
- `name` - the queue name. The other attributes are typically more useful as - `name` - the queue name generated from the worker name. The other attributes
they are more general, but this is available in case a particular queue needs are typically more useful as they are more general, but this is available in
to be selected. case a particular queue needs to be selected. Because this is generated from
the worker name, it does not change based on the result of other routing
rules.
- `resource_boundary` - if the queue is bound by `cpu`, `memory`, or - `resource_boundary` - if the queue is bound by `cpu`, `memory`, or
`unknown`. For example, the `ProjectExportWorker` is memory bound as it has `unknown`. For example, the `ProjectExportWorker` is memory bound as it has
to load data in memory before saving it for export. to load data in memory before saving it for export.
......
...@@ -46,7 +46,7 @@ RSpec.describe Gitlab::SidekiqConfig do ...@@ -46,7 +46,7 @@ RSpec.describe Gitlab::SidekiqConfig do
describe '.workers_for_all_queues_yml' do describe '.workers_for_all_queues_yml' do
it 'returns a tuple with EE workers second' do it 'returns a tuple with EE workers second' do
expect(described_class.workers_for_all_queues_yml.second) expect(described_class.workers_for_all_queues_yml.second)
.to include(an_object_having_attributes(queue: 'repository_update_mirror')) .to include(an_object_having_attributes(generated_queue_name: 'repository_update_mirror'))
end end
end end
......
...@@ -5,7 +5,6 @@ module Gitlab ...@@ -5,7 +5,6 @@ module Gitlab
# For queues that don't have explicit workers - default and mailers # For queues that don't have explicit workers - default and mailers
class DummyWorker class DummyWorker
ATTRIBUTE_METHODS = { ATTRIBUTE_METHODS = {
queue: :queue,
name: :name, name: :name,
feature_category: :get_feature_category, feature_category: :get_feature_category,
has_external_dependencies: :worker_has_external_dependencies?, has_external_dependencies: :worker_has_external_dependencies?,
...@@ -20,6 +19,10 @@ module Gitlab ...@@ -20,6 +19,10 @@ module Gitlab
@attributes = attributes @attributes = attributes
end end
def generated_queue_name
@attributes[:queue]
end
def queue_namespace def queue_namespace
nil nil
end end
......
...@@ -6,9 +6,11 @@ module Gitlab ...@@ -6,9 +6,11 @@ module Gitlab
include Comparable include Comparable
attr_reader :klass attr_reader :klass
delegate :feature_category_not_owned?, :get_feature_category, :get_sidekiq_options,
:get_tags, :get_urgency, :get_weight, :get_worker_resource_boundary, delegate :feature_category_not_owned?, :generated_queue_name, :get_feature_category,
:idempotent?, :queue, :queue_namespace, :worker_has_external_dependencies?, :get_sidekiq_options, :get_tags, :get_urgency, :get_weight,
:get_worker_resource_boundary, :idempotent?, :queue_namespace,
:worker_has_external_dependencies?,
to: :klass to: :klass
def initialize(klass, ee:) def initialize(klass, ee:)
...@@ -35,7 +37,7 @@ module Gitlab ...@@ -35,7 +37,7 @@ module Gitlab
# Put namespaced queues first # Put namespaced queues first
def to_sort def to_sort
[queue_namespace ? 0 : 1, queue] [queue_namespace ? 0 : 1, generated_queue_name]
end end
# YAML representation # YAML representation
...@@ -45,7 +47,7 @@ module Gitlab ...@@ -45,7 +47,7 @@ module Gitlab
def to_yaml def to_yaml
{ {
name: queue, name: generated_queue_name,
worker_name: klass.name, worker_name: klass.name,
feature_category: get_feature_category, feature_category: get_feature_category,
has_external_dependencies: worker_has_external_dependencies?, has_external_dependencies: worker_has_external_dependencies?,
...@@ -62,7 +64,7 @@ module Gitlab ...@@ -62,7 +64,7 @@ module Gitlab
end end
def queue_and_weight def queue_and_weight
[queue, get_weight] [generated_queue_name, get_weight]
end end
def retries def retries
......
...@@ -114,6 +114,13 @@ RSpec.describe Gitlab::SidekiqConfig::WorkerRouter do ...@@ -114,6 +114,13 @@ RSpec.describe Gitlab::SidekiqConfig::WorkerRouter do
['resource_boundary=cpu', 'queue_b'], ['resource_boundary=cpu', 'queue_b'],
['tags=expensive', 'queue_c'] ['tags=expensive', 'queue_c']
] | 'queue_foo' ] | 'queue_foo'
# Match by generated queue name
[
['name=foo_bar', 'queue_foo'],
['feature_category=feature_a|urgency=low', 'queue_a'],
['resource_boundary=cpu', 'queue_b'],
['tags=expensive', 'queue_c']
] | 'queue_foo'
end end
end end
......
...@@ -7,7 +7,7 @@ RSpec.describe Gitlab::SidekiqConfig::Worker do ...@@ -7,7 +7,7 @@ RSpec.describe Gitlab::SidekiqConfig::Worker do
namespace = queue.include?(':') && queue.split(':').first namespace = queue.include?(':') && queue.split(':').first
inner_worker = double( inner_worker = double(
name: attributes[:worker_name] || 'Foo::BarWorker', name: attributes[:worker_name] || 'Foo::BarWorker',
queue: queue, generated_queue_name: queue,
queue_namespace: namespace, queue_namespace: namespace,
get_feature_category: attributes[:feature_category], get_feature_category: attributes[:feature_category],
get_weight: attributes[:weight], get_weight: attributes[:weight],
...@@ -48,9 +48,9 @@ RSpec.describe Gitlab::SidekiqConfig::Worker do ...@@ -48,9 +48,9 @@ RSpec.describe Gitlab::SidekiqConfig::Worker do
describe 'delegations' do describe 'delegations' do
[ [
:feature_category_not_owned?, :get_feature_category, :get_weight, :feature_category_not_owned?, :generated_queue_name,
:get_worker_resource_boundary, :get_urgency, :queue, :get_feature_category, :get_weight, :get_worker_resource_boundary,
:queue_namespace, :worker_has_external_dependencies? :get_urgency, :queue_namespace, :worker_has_external_dependencies?
].each do |meth| ].each do |meth|
it "delegates #{meth} to the worker class" do it "delegates #{meth} to the worker class" do
worker = double worker = double
......
...@@ -28,7 +28,7 @@ RSpec.describe Gitlab::SidekiqConfig do ...@@ -28,7 +28,7 @@ RSpec.describe Gitlab::SidekiqConfig do
describe '.workers_for_all_queues_yml' do describe '.workers_for_all_queues_yml' do
it 'returns a tuple with FOSS workers first' do it 'returns a tuple with FOSS workers first' do
expect(described_class.workers_for_all_queues_yml.first) expect(described_class.workers_for_all_queues_yml.first)
.to include(an_object_having_attributes(queue: 'post_receive')) .to include(an_object_having_attributes(generated_queue_name: 'post_receive'))
end end
end end
......
...@@ -8,17 +8,17 @@ RSpec.describe 'Every Sidekiq worker' do ...@@ -8,17 +8,17 @@ RSpec.describe 'Every Sidekiq worker' do
end end
it 'does not use the default queue' do it 'does not use the default queue' do
expect(workers_without_defaults.map(&:queue)).not_to include('default') expect(workers_without_defaults.map(&:generated_queue_name)).not_to include('default')
end end
it 'uses the cronjob queue when the worker runs as a cronjob' do it 'uses the cronjob queue when the worker runs as a cronjob' do
expect(Gitlab::SidekiqConfig.cron_workers.map(&:queue)).to all(start_with('cronjob:')) expect(Gitlab::SidekiqConfig.cron_workers.map(&:generated_queue_name)).to all(start_with('cronjob:'))
end end
it 'has its queue in Gitlab::SidekiqConfig::QUEUE_CONFIG_PATHS', :aggregate_failures do it 'has its queue in Gitlab::SidekiqConfig::QUEUE_CONFIG_PATHS', :aggregate_failures do
file_worker_queues = Gitlab::SidekiqConfig.worker_queues.to_set file_worker_queues = Gitlab::SidekiqConfig.worker_queues.to_set
worker_queues = Gitlab::SidekiqConfig.workers.map(&:queue).to_set worker_queues = Gitlab::SidekiqConfig.workers.map(&:generated_queue_name).to_set
worker_queues << ActionMailer::MailDeliveryJob.new.queue_name worker_queues << ActionMailer::MailDeliveryJob.new.queue_name
worker_queues << 'default' worker_queues << 'default'
...@@ -33,7 +33,7 @@ RSpec.describe 'Every Sidekiq worker' do ...@@ -33,7 +33,7 @@ RSpec.describe 'Every Sidekiq worker' do
config_queues = Gitlab::SidekiqConfig.config_queues.to_set config_queues = Gitlab::SidekiqConfig.config_queues.to_set
Gitlab::SidekiqConfig.workers.each do |worker| Gitlab::SidekiqConfig.workers.each do |worker|
queue = worker.queue queue = worker.generated_queue_name
queue_namespace = queue.split(':').first queue_namespace = queue.split(':').first
expect(config_queues).to include(queue).or(include(queue_namespace)) expect(config_queues).to include(queue).or(include(queue_namespace))
......
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