From 3917353645b91dae04f7d9b81162fead6f73072a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 28 Apr 2022 17:47:34 +0200 Subject: Fix single Redis connection being used across all threads (#18135) * Fix single Redis connection being used across all Sidekiq threads * Fix tests --- lib/mastodon/feeds_cli.rb | 7 ++++--- lib/mastodon/rack_middleware.rb | 30 ++++++++++++++++++++++++++++++ lib/mastodon/redis_config.rb | 22 +++++++++++++++------- lib/mastodon/sidekiq_middleware.rb | 37 +++++++++++++++++++++++++++++++++++++ lib/sidekiq_error_handler.rb | 24 ------------------------ 5 files changed, 86 insertions(+), 34 deletions(-) create mode 100644 lib/mastodon/rack_middleware.rb create mode 100644 lib/mastodon/sidekiq_middleware.rb delete mode 100644 lib/sidekiq_error_handler.rb (limited to 'lib') diff --git a/lib/mastodon/feeds_cli.rb b/lib/mastodon/feeds_cli.rb index 578ea15c5..428d63a44 100644 --- a/lib/mastodon/feeds_cli.rb +++ b/lib/mastodon/feeds_cli.rb @@ -7,6 +7,7 @@ require_relative 'cli_helper' module Mastodon class FeedsCLI < Thor include CLIHelper + include Redisable def self.exit_on_failure? true @@ -51,10 +52,10 @@ module Mastodon desc 'clear', 'Remove all home and list feeds from Redis' def clear - keys = Redis.current.keys('feed:*') + keys = redis.keys('feed:*') - Redis.current.pipelined do - keys.each { |key| Redis.current.del(key) } + redis.pipelined do + keys.each { |key| redis.del(key) } end say('OK', :green) diff --git a/lib/mastodon/rack_middleware.rb b/lib/mastodon/rack_middleware.rb new file mode 100644 index 000000000..619a2c36d --- /dev/null +++ b/lib/mastodon/rack_middleware.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class Mastodon::RackMiddleware + def initialize(app) + @app = app + end + + def call(env) + @app.call(env) + ensure + clean_up_sockets! + end + + private + + def clean_up_sockets! + clean_up_redis_socket! + clean_up_statsd_socket! + end + + def clean_up_redis_socket! + Thread.current[:redis]&.close + Thread.current[:redis] = nil + end + + def clean_up_statsd_socket! + Thread.current[:statsd_socket]&.close + Thread.current[:statsd_socket] = nil + end +end diff --git a/lib/mastodon/redis_config.rb b/lib/mastodon/redis_config.rb index 5bfd26e34..98dc4788d 100644 --- a/lib/mastodon/redis_config.rb +++ b/lib/mastodon/redis_config.rb @@ -11,13 +11,15 @@ def setup_redis_env_url(prefix = nil, defaults = true) port = ENV.fetch(prefix + 'REDIS_PORT') { 6379 if defaults } db = ENV.fetch(prefix + 'REDIS_DB') { 0 if defaults } - ENV[prefix + 'REDIS_URL'] = if [password, host, port, db].all?(&:nil?) - ENV['REDIS_URL'] - else - Addressable::URI.parse("redis://#{host}:#{port}/#{db}").tap do |uri| - uri.password = password if password.present? - end.normalize.to_str - end + ENV[prefix + 'REDIS_URL'] = begin + if [password, host, port, db].all?(&:nil?) + ENV['REDIS_URL'] + else + Addressable::URI.parse("redis://#{host}:#{port}/#{db}").tap do |uri| + uri.password = password if password.present? + end.normalize.to_str + end + end end setup_redis_env_url @@ -33,6 +35,8 @@ REDIS_CACHE_PARAMS = { url: ENV['CACHE_REDIS_URL'], expires_in: 10.minutes, namespace: cache_namespace, + pool_size: Sidekiq.server? ? Sidekiq.options[:concurrency] : Integer(ENV['MAX_THREADS'] || 5), + pool_timeout: 5, }.freeze REDIS_SIDEKIQ_PARAMS = { @@ -40,3 +44,7 @@ REDIS_SIDEKIQ_PARAMS = { url: ENV['SIDEKIQ_REDIS_URL'], namespace: sidekiq_namespace, }.freeze + +if Rails.env.test? + ENV['REDIS_NAMESPACE'] = "mastodon_test#{ENV['TEST_ENV_NUMBER']}" +end diff --git a/lib/mastodon/sidekiq_middleware.rb b/lib/mastodon/sidekiq_middleware.rb new file mode 100644 index 000000000..7ec4097df --- /dev/null +++ b/lib/mastodon/sidekiq_middleware.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +class Mastodon::SidekiqMiddleware + BACKTRACE_LIMIT = 3 + + def call(*) + yield + rescue Mastodon::HostValidationError + # Do not retry + rescue => e + limit_backtrace_and_raise(e) + ensure + clean_up_sockets! + end + + private + + def limit_backtrace_and_raise(exception) + exception.set_backtrace(exception.backtrace.first(BACKTRACE_LIMIT)) + raise exception + end + + def clean_up_sockets! + clean_up_redis_socket! + clean_up_statsd_socket! + end + + def clean_up_redis_socket! + Thread.current[:redis]&.close + Thread.current[:redis] = nil + end + + def clean_up_statsd_socket! + Thread.current[:statsd_socket]&.close + Thread.current[:statsd_socket] = nil + end +end diff --git a/lib/sidekiq_error_handler.rb b/lib/sidekiq_error_handler.rb deleted file mode 100644 index 358afd540..000000000 --- a/lib/sidekiq_error_handler.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -class SidekiqErrorHandler - BACKTRACE_LIMIT = 3 - - def call(*) - yield - rescue Mastodon::HostValidationError - # Do not retry - rescue => e - limit_backtrace_and_raise(e) - ensure - socket = Thread.current[:statsd_socket] - socket&.close - Thread.current[:statsd_socket] = nil - end - - private - - def limit_backtrace_and_raise(exception) - exception.set_backtrace(exception.backtrace.first(BACKTRACE_LIMIT)) - raise exception - end -end -- cgit