really fix disconnect_if_idle for Redis cluster

Cluster's internal structure of Redis clients is quite different,
so we can't just throw disconnect_if_idle on there

fixes AE-751

Change-Id: Ie967460078061dbf3754210f40fa6bd189bf26da
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/340996
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Isaac Moore <isaac.moore@instructure.com>
QA-Review: Cody Cutrer <cody@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
This commit is contained in:
Cody Cutrer 2024-02-21 14:31:35 -07:00
parent 87ffc7a091
commit c05e453740
2 changed files with 48 additions and 13 deletions

View File

@ -49,6 +49,12 @@ module CanvasCache
end
end
module Cluster
def disconnect_if_idle(since_when)
@router.instance_variable_get(:@node).clients.each { |c| c.disconnect_if_idle(since_when) }
end
end
module IgnorePipelinedKey
def pipelined(_key = nil, **kwargs, &)
# ignore key; only useful for distributed
@ -159,7 +165,8 @@ module CanvasCache
::Redis::Scripting::Module.prepend(Scripting::Module) if defined?(::Redis::Scripting::Module)
::Redis.prepend(Redis)
::Redis.prepend(IgnorePipelinedKey)
::RedisClient::Cluster.prepend(Client)
::RedisClient.prepend(Client)
::Redis::Cluster::Client.prepend(Cluster)
::RedisClient::Cluster.prepend(IgnorePipelinedKey)
::Redis::Client.prepend(Client)
::Redis::Distributed.prepend(Distributed)

View File

@ -18,6 +18,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
require "redis/cluster"
require "spec_helper"
require "timecop"
@ -310,22 +311,49 @@ describe CanvasCache::Redis do
describe "#disconnect_if_idle" do
let(:redis) { CanvasCache::Redis.redis }
let(:client) { redis._client }
let(:raw_client) { client }
it "closes the connection if no command was ever received" do
expect(client).to receive(:close)
client.disconnect_if_idle(Process.clock_gettime(Process::CLOCK_MONOTONIC))
shared_examples "disconnect_if_idle" do
it "closes the connection if no command was ever received" do
expect(raw_client).to receive(:close)
client.disconnect_if_idle(Process.clock_gettime(Process::CLOCK_MONOTONIC))
end
it "does not close the connection if a commmand was recently received" do
redis.get("key")
expect(raw_client).not_to receive(:close)
client.disconnect_if_idle(Process.clock_gettime(Process::CLOCK_MONOTONIC) - 10)
end
it "closes the connection if a commmand was received, but not recently" do
redis.get("key")
expect(raw_client).to receive(:close)
client.disconnect_if_idle(Process.clock_gettime(Process::CLOCK_MONOTONIC) + 10)
end
end
it "does not close the connection if a commmand was recently received" do
redis.get("key")
expect(client).not_to receive(:close)
client.disconnect_if_idle(Process.clock_gettime(Process::CLOCK_MONOTONIC) - 10)
end
include_examples "disconnect_if_idle"
it "closes the connection if a commmand was received, but not recently" do
redis.get("key")
expect(client).to receive(:close)
client.disconnect_if_idle(Process.clock_gettime(Process::CLOCK_MONOTONIC) + 10)
context "with a cluster" do
let(:redis) do
allow_any_instance_of(RedisClient::Cluster::Node).to receive(:refetch_node_info_list).and_return(
[RedisClient::Cluster::Node::Info.new(
id: "id",
node_key: "#{CanvasCache::Redis.redis._client.host}:#{CanvasCache::Redis.redis._client.port}",
role: "master",
primary_id: "-",
slots: [[0, 16_383]]
)]
)
Redis::Cluster.new(nodes: [CanvasCache::Redis.redis.id], connect_with_original_config: true)
end
let(:raw_client) do
router = client.instance_variable_get(:@router)
router.find_node(router.find_node_key(""))
end
include_examples "disconnect_if_idle"
end
end
end