# frozen_string_literal: true module Gitlab # The SidekiqMiddleware class is responsible for configuring the # middleware stacks used in the client and server middlewares module SidekiqMiddleware class Client def self.middlewares [ # ConcurrencyLimit::Resume needs to be first and before Labkit and ConcurrencyLimit::Client ::Gitlab::SidekiqMiddleware::ConcurrencyLimit::Resume, ::Gitlab::SidekiqMiddleware::WorkerContext::Client, # needs to be before the Labkit middleware ::Labkit::Middleware::Sidekiq::Client, # Sidekiq Client Middleware should be placed before DuplicateJobs::Client middleware, # so we can store WAL location before we deduplicate the job. ::Gitlab::Database::LoadBalancing::SidekiqClientMiddleware, ::Gitlab::SidekiqMiddleware::PauseControl::Client, ::Gitlab::SidekiqMiddleware::ConcurrencyLimit::Client, # NOTE: Everything from DuplicateJobs::Client to DuplicateJobs::Server must yield # no returning or job interception as it will leave the duplicate job redis key # dangling and errorneously deduplicating future jobs until key expires. ::Gitlab::SidekiqMiddleware::DuplicateJobs::Client, ::Gitlab::SidekiqStatus::ClientMiddleware, ::Gitlab::SidekiqMiddleware::AdminMode::Client, # Size limiter should be placed at the bottom, but before the metrics middleware # NOTE: this raises error after the duplicate jobs middleware but is acceptable # since jobs that are too large should not be enqueued. ::Gitlab::SidekiqMiddleware::SizeLimiter::Client, ::Gitlab::SidekiqMiddleware::ClientMetrics, ::Gitlab::SidekiqMiddleware::Identity::Passthrough ] end # The result of this method should be passed to # Sidekiq's `config.client_middleware` method # eg: `config.client_middleware(&Gitlab::SidekiqMiddleware::Client.configurator)` def self.configurator ->(chain) do middlewares.each { |middleware| chain.add(middleware) } end end end class Server def self.middlewares(metrics: true, arguments_logger: true, skip_jobs: true) [ # Size limiter should be placed at the top ::Gitlab::SidekiqMiddleware::SizeLimiter::Server, ::Gitlab::SidekiqMiddleware::ShardAwarenessValidator, ::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). ::Labkit::Middleware::Sidekiq::Server, ::Gitlab::SidekiqMiddleware::RequestStoreMiddleware, ::Gitlab::QueryLimiting.enabled_for_env? ? ::Gitlab::QueryLimiting::SidekiqMiddleware : nil, metrics ? ::Gitlab::SidekiqMiddleware::ServerMetrics : nil, arguments_logger ? ::Gitlab::SidekiqMiddleware::ArgumentsLogger : nil, ::Gitlab::SidekiqMiddleware::ExtraDoneLogMetadata, ::Gitlab::SidekiqMiddleware::BatchLoader, ::Gitlab::SidekiqMiddleware::InstrumentationLogger, ::Gitlab::SidekiqMiddleware::SetIpAddress, ::Gitlab::SidekiqMiddleware::AdminMode::Server, ::Gitlab::SidekiqMiddleware::QueryAnalyzer, ::Gitlab::SidekiqVersioning::Middleware, ::Gitlab::SidekiqStatus::ServerMiddleware, ::Gitlab::SidekiqMiddleware::WorkerContext::Server, ::ClickHouse::MigrationSupport::SidekiqMiddleware, # DuplicateJobs::Server should be placed at the bottom, but before the SidekiqServerMiddleware, # so we can compare the latest WAL location against replica # NOTE: Everything from DuplicateJobs::Client to DuplicateJobs::Server must yield # no returning or job interception as it will leave the duplicate job redis key # dangling and errorneously deduplicating future jobs until key expires. # Any middlewares after DuplicateJobs::Server can return/intercept jobs. ::Gitlab::SidekiqMiddleware::DuplicateJobs::Server, ::Gitlab::SidekiqMiddleware::PauseControl::Server, ::Gitlab::SidekiqMiddleware::Throttling::Server, ::Gitlab::SidekiqMiddleware::ConcurrencyLimit::Server, skip_jobs ? ::Gitlab::SidekiqMiddleware::SkipJobs : nil, ::Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, ::Gitlab::SidekiqMiddleware::ResourceUsageLimit::Server, ::Gitlab::SidekiqMiddleware::Identity::Restore ].compact end # The result of this method should be passed to # Sidekiq's `config.server_middleware` method # eg: `config.server_middleware(&Gitlab::SidekiqMiddleware::Server.configurator)` def self.configurator(metrics: true, arguments_logger: true, skip_jobs: true) ->(chain) do middlewares(metrics: metrics, arguments_logger: arguments_logger, skip_jobs: skip_jobs).each do |middleware| chain.add(middleware) end ::Gitlab::SidekiqMiddleware::ServerMetrics.initialize_process_metrics if metrics end end end end end Gitlab::SidekiqMiddleware::Client.prepend_mod Gitlab::SidekiqMiddleware::Server.prepend_mod