Feature Categorization
Introduced in GitLab 13.2.
Each Sidekiq worker, Batched Background migrations, controller action, test example or API endpoint
must declare a feature_category
attribute. This attribute maps each
of these to a feature category. This
is done for error budgeting, alert routing, and team attribution.
The list of feature categories can be found in the file config/feature_categories.yml
.
This file is generated from the
stages.yml
data file used in the GitLab Handbook and other GitLab resources.
config/feature_categories.yml
Updating Occasionally new features will be added to GitLab stages, groups, and
product categories. When this occurs, you can automatically update
config/feature_categories.yml
by running
scripts/update-feature-categories
. This script will fetch and parse
stages.yml
and generate a new version of the file, which needs to be committed to
the repository.
The Scalability team
currently maintains the feature_categories.yml
file. They will automatically be
notified on Slack when the file becomes outdated.
Sidekiq workers
The declaration uses the feature_category
class method, as shown below.
class SomeScheduledTaskWorker
include ApplicationWorker
# Declares that this worker is part of the
# `continuous_integration` feature category
feature_category :continuous_integration
# ...
end
The feature categories specified using feature_category
should be
defined in
config/feature_categories.yml
. If
not, the specs will fail.
Excluding Sidekiq workers from feature categorization
A few Sidekiq workers, that are used across all features, cannot be mapped to a
single category. These should be declared as such using the
feature_category :not_owned
declaration, as shown below:
class SomeCrossCuttingConcernWorker
include ApplicationWorker
# Declares that this worker does not map to a feature category
feature_category :not_owned # rubocop:disable Gitlab/AvoidFeatureCategoryNotOwned
# ...
end
When possible, workers marked as "not owned" use their caller's
category (worker or HTTP endpoint) in metrics and logs.
For instance, ReactiveCachingWorker
can have multiple feature
categories in metrics and logs.
Batched background migrations
Long-running migrations (as per the time limits guidelines)
are pulled out as batched background migrations.
They should define a feature_category
, like this:
# File name: lib/gitlab/background_migration/my_background_migration_job.rb
class MyBackgroundMigrationJob < BatchedMigrationJob
feature_category :gitaly
#...
end
NOTE:
RuboCop::Cop::BackgroundMigration::FeatureCategory
cop ensures a valid feature_category
is defined.
Rails controllers
Specifying feature categories on controller actions can be done using
the feature_category
class method.
A feature category can be specified on an entire controller using:
class Boards::ListsController < ApplicationController
feature_category :kanban_boards
end
The feature category can be limited to a list of actions using the second argument:
class DashboardController < ApplicationController
feature_category :team_planning, [:issues, :issues_calendar]
feature_category :code_review_workflow, [:merge_requests]
end
These forms cannot be mixed: if a controller has more than one category, every single action must be listed.
Excluding controller actions from feature categorization
In the rare case an action cannot be tied to a feature category this
can be done using the not_owned
feature category.
class Admin::LogsController < ApplicationController
feature_category :not_owned
end
Ensuring feature categories are valid
The spec/controllers/every_controller_spec.rb
will iterate over all
defined routes, and check the controller to see if a category is
assigned to all actions.
The spec also validates if the used feature categories are known. And if the actions used in configuration still exist as routes.
API endpoints
The GraphQL API is currently categorized
as not_owned
. For now, no extra specification is needed. For more
information, see
gitlab-com/gl-infra/scalability#583
.
Grape API endpoints can use the feature_category
class method, like
Rails controllers do:
module API
class Issues < ::API::Base
feature_category :team_planning
end
end
The second argument can be used to specify feature categories for specific routes:
module API
class Users < ::API::Base
feature_category :user_profile, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key']
end
end
Or the feature category can be specified in the action itself:
module API
class Users < ::API::Base
get ':id', feature_category: :user_profile do
end
end
end
As with Rails controllers, an API class must specify the category for every single action unless the same category is used for every action within that class.
RSpec Examples
You must set feature category metadata for each RSpec example. This information is used for flaky test issues to identify the group that owns the feature.
The feature_category
should be a value from config/feature_categories.yml
.
The feature_category
metadata can be set:
Consider splitting the file in the case there are multiple feature categories identified in the same file.
Example:
RSpec.describe Admin::Geo::SettingsController, :geo, feature_category: :geo_replication do
For examples that don't have a feature_category
set we add a warning when running them in local environment.
To disable the warning use RSPEC_WARN_MISSING_FEATURE_CATEGORY=false
when running RSpec tests:
RSPEC_WARN_MISSING_FEATURE_CATEGORY=false bin/rspec spec/<test_file>
Additionally, we flag the offenses via RSpec/MissingFeatureCategory
RuboCop rule.
Tooling feature category
For Engineering Productivity internal tooling we use feature_category: :tooling
.
For example in spec/tooling/danger/specs_spec.rb
.
Shared feature category
For features that support developers and they are not specific to a product group we use feature_category: :shared
For example spec/lib/gitlab/job_waiter_spec.rb