mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 15:25:35 +08:00
PERF: Redis snapshotting during tests (#15260)
We can fake redis transactions so that `fab!` works for redis and PG data, but it's too slow to be used indiscriminately. Instead, you can opt into it with the `use_redis_snapshotting` helper. Insofar as snapshotting allows us to `fab!` more things, it provides a speedup.
This commit is contained in:
parent
e42f33b6ba
commit
02245ce41f
|
@ -53,7 +53,8 @@ class DiscourseRedis
|
||||||
:msetnx, :persist, :pexpire, :pexpireat, :psetex, :pttl, :rename, :renamenx, :rpop, :rpoplpush, :rpush, :rpushx, :sadd, :scard,
|
:msetnx, :persist, :pexpire, :pexpireat, :psetex, :pttl, :rename, :renamenx, :rpop, :rpoplpush, :rpush, :rpushx, :sadd, :scard,
|
||||||
:sdiff, :set, :setbit, :setex, :setnx, :setrange, :sinter, :sismember, :smembers, :sort, :spop, :srandmember, :srem, :strlen,
|
:sdiff, :set, :setbit, :setex, :setnx, :setrange, :sinter, :sismember, :smembers, :sort, :spop, :srandmember, :srem, :strlen,
|
||||||
:sunion, :ttl, :type, :watch, :zadd, :zcard, :zcount, :zincrby, :zrange, :zrangebyscore, :zrank, :zrem, :zremrangebyrank,
|
:sunion, :ttl, :type, :watch, :zadd, :zcard, :zcount, :zincrby, :zrange, :zrangebyscore, :zrank, :zrem, :zremrangebyrank,
|
||||||
:zremrangebyscore, :zrevrange, :zrevrangebyscore, :zrevrank, :zrangebyscore ].each do |m|
|
:zremrangebyscore, :zrevrange, :zrevrangebyscore, :zrevrank, :zrangebyscore,
|
||||||
|
:dump, :restore].each do |m|
|
||||||
define_method m do |*args, **kwargs|
|
define_method m do |*args, **kwargs|
|
||||||
args[0] = "#{namespace}:#{args[0]}" if @namespace
|
args[0] = "#{namespace}:#{args[0]}" if @namespace
|
||||||
DiscourseRedis.ignore_readonly { @redis.public_send(m, *args, **kwargs) }
|
DiscourseRedis.ignore_readonly { @redis.public_send(m, *args, **kwargs) }
|
||||||
|
|
41
lib/redis_snapshot.rb
Normal file
41
lib/redis_snapshot.rb
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class RedisSnapshot
|
||||||
|
def self.begin_faux_transaction(redis = Discourse.redis)
|
||||||
|
@stack ||= []
|
||||||
|
@stack.push(RedisSnapshot.load(redis))
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.end_faux_transaction(redis = Discourse.redis)
|
||||||
|
@stack.pop.restore(redis)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.load(redis = Discourse.redis)
|
||||||
|
keys = redis.keys
|
||||||
|
|
||||||
|
values =
|
||||||
|
redis.pipelined do
|
||||||
|
keys.each do |key|
|
||||||
|
redis.dump(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
new(keys.zip(values).delete_if { |k, v| v.nil? })
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(dump)
|
||||||
|
@dump = dump
|
||||||
|
end
|
||||||
|
|
||||||
|
def restore(redis = Discourse.redis)
|
||||||
|
redis.pipelined do
|
||||||
|
redis.flushdb
|
||||||
|
|
||||||
|
@dump.each do |key, value|
|
||||||
|
redis.restore(key, 0, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
21
spec/helpers/redis_snapshot_helper.rb
Normal file
21
spec/helpers/redis_snapshot_helper.rb
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module RedisSnapshotHelper
|
||||||
|
def use_redis_snapshotting
|
||||||
|
before(:all) do
|
||||||
|
RedisSnapshot.begin_faux_transaction
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:all) do
|
||||||
|
RedisSnapshot.end_faux_transaction
|
||||||
|
end
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
RedisSnapshot.begin_faux_transaction
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:each) do
|
||||||
|
RedisSnapshot.end_faux_transaction
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -78,6 +78,7 @@ end
|
||||||
# in spec/support/ and its subdirectories.
|
# in spec/support/ and its subdirectories.
|
||||||
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
|
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
|
||||||
Dir[Rails.root.join("spec/fabricators/*.rb")].each { |f| require f }
|
Dir[Rails.root.join("spec/fabricators/*.rb")].each { |f| require f }
|
||||||
|
require_relative './helpers/redis_snapshot_helper'
|
||||||
|
|
||||||
# Require plugin helpers at plugin/[plugin]/spec/plugin_helper.rb (includes symlinked plugins).
|
# Require plugin helpers at plugin/[plugin]/spec/plugin_helper.rb (includes symlinked plugins).
|
||||||
if ENV['LOAD_PLUGINS'] == "1"
|
if ENV['LOAD_PLUGINS'] == "1"
|
||||||
|
@ -181,6 +182,7 @@ end
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
config.fail_fast = ENV['RSPEC_FAIL_FAST'] == "1"
|
config.fail_fast = ENV['RSPEC_FAIL_FAST'] == "1"
|
||||||
config.silence_filter_announcements = ENV['RSPEC_SILENCE_FILTER_ANNOUNCEMENTS'] == "1"
|
config.silence_filter_announcements = ENV['RSPEC_SILENCE_FILTER_ANNOUNCEMENTS'] == "1"
|
||||||
|
config.extend RedisSnapshotHelper
|
||||||
config.include Helpers
|
config.include Helpers
|
||||||
config.include MessageBus
|
config.include MessageBus
|
||||||
config.include RSpecHtmlMatchers
|
config.include RSpecHtmlMatchers
|
||||||
|
|
|
@ -1756,11 +1756,13 @@ RSpec.describe TopicsController do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#show' do
|
describe '#show' do
|
||||||
fab!(:private_topic) { Fabricate(:private_message_topic) }
|
use_redis_snapshotting
|
||||||
let!(:topic) { Fabricate(:post).topic }
|
|
||||||
|
|
||||||
let!(:p1) { Fabricate(:post, user: topic.user) }
|
fab!(:private_topic) { Fabricate(:private_message_topic) }
|
||||||
let!(:p2) { Fabricate(:post, user: topic.user) }
|
fab!(:topic) { Fabricate(:post).topic }
|
||||||
|
|
||||||
|
fab!(:p1) { Fabricate(:post, user: topic.user) }
|
||||||
|
fab!(:p2) { Fabricate(:post, user: topic.user) }
|
||||||
|
|
||||||
describe 'when topic is not allowed' do
|
describe 'when topic is not allowed' do
|
||||||
it 'should return the right response' do
|
it 'should return the right response' do
|
||||||
|
|
Loading…
Reference in New Issue
Block a user