Skip to content

Commit

Permalink
Global namespacing that applies to all threads
Browse files Browse the repository at this point in the history
Namespacing is thread-local currently, so it's easy to lose, e.g.
when running parallel tests, Capybara tests, or executor pools.

Changing that is a major compatibility break, so we introduce a
non-thread-local Kredis.global_namespace attribute that behaves
as we'd expect.

When Kredis.namespace is set, it's appended to the global namespace.

This flushed out other library bugs, suggesting that namespacing
may not be widely used.
  • Loading branch information
jeremy committed Dec 19, 2024
1 parent 8850def commit 0d6b42f
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 38 deletions.
16 changes: 13 additions & 3 deletions lib/kredis/namespace.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
# frozen_string_literal: true

module Kredis::Namespace
def namespace=(namespace)
Thread.current[:kredis_namespace] = namespace
attr_accessor :global_namespace

def namespace=(value)
if global_namespace
if value
value = "#{global_namespace}:#{value}"
else
value = global_namespace
end
end

Thread.current[:kredis_namespace] = value
end

def namespace
Thread.current[:kredis_namespace]
Thread.current[:kredis_namespace] ||= global_namespace
end

def namespaced_key(key)
Expand Down
14 changes: 2 additions & 12 deletions lib/kredis/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,8 @@ class Kredis::Railtie < ::Rails::Railtie

initializer "kredis.testing" do
ActiveSupport.on_load(:active_support_test_case) do
$kredis_parallel_worker = nil
parallelize_setup { |worker| $kredis_parallel_worker = worker }

setup do
@original_namespace = Kredis.namespace
Kredis.namespace = [ @original_namespace, :test, $kredis_parallel_worker ].compact.join("-")
end

teardown do
Kredis.clear_all
Kredis.namespace = @original_namespace
end
parallelize_setup { |worker| Kredis.global_namespace = [ Kredis.global_namespace, :test, worker ].compact.join("-") }
teardown { Kredis.clear_all }
end
end

Expand Down
18 changes: 9 additions & 9 deletions test/attributes_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,12 @@ class AttributesTest < ActiveSupport::TestCase

test "proxy with custom string key" do
@person.nothing.set "everything"
assert_equal "everything", Kredis.redis.get("something:else")
assert_equal "everything", Kredis.redis.get(Kredis.namespaced_key("something:else"))
end

test "proxy with custom proc key" do
@person.something.set "everything"
assert_equal "everything", Kredis.redis.get("person:8:something")
assert_equal "everything", Kredis.redis.get(Kredis.namespaced_key("person:8:something"))
end

test "list" do
Expand All @@ -135,17 +135,17 @@ class AttributesTest < ActiveSupport::TestCase

test "list with custom proc key" do
@person.names_with_custom_key_via_lambda.append(%w[ david kasper ])
assert_equal %w[ david kasper ], Kredis.redis.lrange("person:8:names_customized", 0, -1)
assert_equal %w[ david kasper ], Kredis.redis.lrange(Kredis.namespaced_key("person:8:names_customized"), 0, -1)
end

test "list with custom method key" do
@person.names_with_custom_key_via_method.append(%w[ david kasper ])
assert_equal %w[ david kasper ], Kredis.redis.lrange("some-generated-key", 0, -1)
assert_equal %w[ david kasper ], Kredis.redis.lrange(Kredis.namespaced_key("some-generated-key"), 0, -1)
end

test "list with default proc value" do
assert_equal %w[ Random Jason ], @person.names_with_default_via_lambda.elements
assert_equal %w[ Random Jason ], Kredis.redis.lrange("people:8:names_with_default_via_lambda", 0, -1)
assert_equal %w[ Random Jason ], Kredis.redis.lrange(Kredis.namespaced_key("people:8:names_with_default_via_lambda"), 0, -1)
end

test "unique list" do
Expand All @@ -157,7 +157,7 @@ class AttributesTest < ActiveSupport::TestCase

test "unique list with default proc value" do
assert_equal %w[ Random Jason ], @person.skills_with_default_via_lambda.elements
assert_equal %w[ Random Jason ], Kredis.redis.lrange("people:8:skills_with_default_via_lambda", 0, -1)
assert_equal %w[ Random Jason ], Kredis.redis.lrange(Kredis.namespaced_key("people:8:skills_with_default_via_lambda"), 0, -1)
end

test "ordered set" do
Expand Down Expand Up @@ -222,7 +222,7 @@ class AttributesTest < ActiveSupport::TestCase
end

test "float with default proc value" do
assert_not_equal 73.2, Kredis.redis.get("people:8:height_with_default_via_lambda")
assert_not_equal 73.2, Kredis.redis.get(Kredis.namespaced_key("people:8:height_with_default_via_lambda"))
assert_equal 73.2, @person.height_with_default_via_lambda.value
assert_equal "73.2", @person.height_with_default_via_lambda.to_s
end
Expand Down Expand Up @@ -321,7 +321,7 @@ class AttributesTest < ActiveSupport::TestCase

test "set with default proc value" do
assert_equal [ "Paris" ], @person.vacations_with_default_via_lambda.members
assert_equal [ "Paris" ], Kredis.redis.smembers("people:8:vacations_with_default_via_lambda")
assert_equal [ "Paris" ], Kredis.redis.smembers(Kredis.namespaced_key("people:8:vacations_with_default_via_lambda"))
end

test "json" do
Expand All @@ -332,7 +332,7 @@ class AttributesTest < ActiveSupport::TestCase
test "json with default proc value" do
expect = { "height" => 73.2, "weight" => 182.4, "eye_color" => "ha" }
assert_equal expect, @person.settings_with_default_via_lambda.value
assert_equal expect.to_json, Kredis.redis.get("people:8:settings_with_default_via_lambda")
assert_equal expect.to_json, Kredis.redis.get(Kredis.namespaced_key("people:8:settings_with_default_via_lambda"))
end


Expand Down
11 changes: 9 additions & 2 deletions test/connections_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@
require "yaml"

class ConnectionsTest < ActiveSupport::TestCase
setup { Kredis.connections = {} }
teardown { Kredis.namespace = nil }
setup do
Kredis.connections = {}
@original_global_namespace, Kredis.global_namespace = Kredis.global_namespace, nil
end

teardown do
Kredis.global_namespace = @original_global_namespace
Kredis.namespace = nil
end

test "clear all" do
list = Kredis.list "mylist"
Expand Down
28 changes: 16 additions & 12 deletions test/migration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,36 @@
require "test_helper"

class MigrationTest < ActiveSupport::TestCase
setup { @proxy = Kredis.string "new_proxy" }

test "migrate_all" do
3.times { |index| Kredis.proxy("mykey:#{index}").set "hello there #{index}" }

Kredis::Migration.migrate_all("mykey:*") { |key| key.gsub("mykey", "thykey") }
Kredis::Migration.migrate_all(Kredis.namespaced_key("mykey:*")) { |key| "thykey:#{key.split(":").last}" }

3.times do |index|
assert_equal "hello there #{index}", Kredis.proxy("thykey:#{index}").get
end
end

test "migrate" do
@original_global_namespace, Kredis.global_namespace = Kredis.global_namespace, nil

old_proxy = Kredis.string "old_proxy"
old_proxy.set "hello there"
assert_not @proxy.assigned?

Kredis::Migration.migrate from: "old_proxy", to: @proxy.key
assert_equal "hello there", @proxy.value
new_proxy = Kredis.string "new_proxy"
assert_not new_proxy.assigned?

Kredis::Migration.migrate from: Kredis.namespaced_key("old_proxy"), to: "new_proxy"
assert_equal "hello there", new_proxy.value
assert old_proxy.assigned?, "just copying the data"
ensure
Kredis.global_namespace = @original_global_namespace
end

test "migrate with blank keys" do
assert_nothing_raised do
Kredis::Migration.migrate from: "old_key", to: nil
Kredis::Migration.migrate from: "old_key", to: ""
Kredis::Migration.migrate from: Kredis.namespaced_key("old_key"), to: nil
Kredis::Migration.migrate from: Kredis.namespaced_key("old_key"), to: ""
end
end

Expand All @@ -37,7 +41,7 @@ class MigrationTest < ActiveSupport::TestCase

Kredis.namespace = "migrate"

Kredis::Migration.migrate from: "key", to: "key"
Kredis::Migration.migrate from: "#{Kredis.global_namespace}:key", to: "key"

assert_equal "x", Kredis.proxy("key").get
ensure
Expand All @@ -47,7 +51,7 @@ class MigrationTest < ActiveSupport::TestCase
test "migrate with automatic id extraction" do
Kredis.proxy("mykey:1").set "hey"

Kredis::Migration.migrate_all "mykey:*" do |key, id|
Kredis::Migration.migrate_all Kredis.namespaced_key("mykey:*") do |key, id|
assert_equal 1, id
key
end
Expand All @@ -56,15 +60,15 @@ class MigrationTest < ActiveSupport::TestCase
test "delete_all with pattern" do
3.times { |index| Kredis.proxy("mykey:#{index}").set "hello there #{index}" }

Kredis::Migration.delete_all "mykey:*"
Kredis::Migration.delete_all Kredis.namespaced_key("mykey:*")

3.times { |index| assert_nil Kredis.proxy("mykey:#{index}").get }
end

test "delete_all with keys" do
3.times { |index| Kredis.proxy("mykey:#{index}").set "hello there #{index}" }

Kredis::Migration.delete_all(*3.times.map { |index| "mykey:#{index}" })
Kredis::Migration.delete_all(*3.times.map { |index| Kredis.namespaced_key("mykey:#{index}") })

3.times { |index| assert_nil Kredis.proxy("mykey:#{index}").get }
end
Expand Down
2 changes: 2 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

require "kredis"

Kredis.global_namespace = "kredis-test"

Kredis.configurator = Class.new do
def config_for(name) { db: "1" } end
def root() Pathname.new(".") end
Expand Down

0 comments on commit 0d6b42f

Please sign in to comment.