mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-06 15:02:13 +00:00
fix(cache): use key versioning (#10657)
# Which Problems Are Solved
Cached object may have a different schema between Zitadel versions.
# How the Problems Are Solved
Use the curent build version in DB based cache connectors PostgreSQL and
Redis.
# Additional Changes
- Cleanup the ZitadelVersion field from the authz Instance
- Solve potential race condition on global variables in build package.
# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/10648
- Obsoletes https://github.com/zitadel/zitadel/pull/10646
- Needs to be back-ported to v4 over
https://github.com/zitadel/zitadel/pull/10645
(cherry picked from commit f6f37d3a31)
This commit is contained in:
committed by
Livio Spring
parent
f9b3c1ef50
commit
6e90d4a927
26
internal/cache/connector/redis/redis.go
vendored
26
internal/cache/connector/redis/redis.go
vendored
@@ -38,21 +38,23 @@ var (
|
||||
)
|
||||
|
||||
type redisCache[I, K comparable, V cache.Entry[I, K]] struct {
|
||||
db int
|
||||
config *cache.Config
|
||||
indices []I
|
||||
connector *Connector
|
||||
logger *slog.Logger
|
||||
db int
|
||||
zitadelVersion string
|
||||
config *cache.Config
|
||||
indices []I
|
||||
connector *Connector
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// NewCache returns a cache that stores and retrieves object using single Redis.
|
||||
func NewCache[I, K comparable, V cache.Entry[I, K]](config cache.Config, client *Connector, db int, indices []I) cache.Cache[I, K, V] {
|
||||
func NewCache[I, K comparable, V cache.Entry[I, K]](config cache.Config, zitadelVersion string, client *Connector, db int, indices []I) cache.Cache[I, K, V] {
|
||||
return &redisCache[I, K, V]{
|
||||
config: &config,
|
||||
db: db,
|
||||
indices: indices,
|
||||
connector: client,
|
||||
logger: config.Log.Slog(),
|
||||
config: &config,
|
||||
zitadelVersion: zitadelVersion,
|
||||
db: db,
|
||||
indices: indices,
|
||||
connector: client,
|
||||
logger: config.Log.Slog(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +168,7 @@ func (c *redisCache[I, K, V]) Truncate(ctx context.Context) (err error) {
|
||||
func (c *redisCache[I, K, V]) redisIndexKeys(index I, keys ...K) []string {
|
||||
out := make([]string, len(keys))
|
||||
for i, k := range keys {
|
||||
out[i] = fmt.Sprintf("%v:%v", index, k)
|
||||
out[i] = fmt.Sprintf("%s:%v:%v", c.zitadelVersion, index, k)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
26
internal/cache/connector/redis/redis_test.go
vendored
26
internal/cache/connector/redis/redis_test.go
vendored
@@ -68,9 +68,9 @@ func Test_redisCache_set(t *testing.T) {
|
||||
},
|
||||
},
|
||||
assertions: func(t *testing.T, s *miniredis.Miniredis, objectID string) {
|
||||
s.CheckGet(t, "0:one", objectID)
|
||||
s.CheckGet(t, "1:foo", objectID)
|
||||
s.CheckGet(t, "1:bar", objectID)
|
||||
s.CheckGet(t, "VERSION:0:one", objectID)
|
||||
s.CheckGet(t, "VERSION:1:foo", objectID)
|
||||
s.CheckGet(t, "VERSION:1:bar", objectID)
|
||||
assert.Empty(t, s.HGet(objectID, "expiry"))
|
||||
assert.JSONEq(t, `{"ID":"one","Name":["foo","bar"]}`, s.HGet(objectID, "object"))
|
||||
},
|
||||
@@ -88,9 +88,9 @@ func Test_redisCache_set(t *testing.T) {
|
||||
},
|
||||
},
|
||||
assertions: func(t *testing.T, s *miniredis.Miniredis, objectID string) {
|
||||
s.CheckGet(t, "0:one", objectID)
|
||||
s.CheckGet(t, "1:foo", objectID)
|
||||
s.CheckGet(t, "1:bar", objectID)
|
||||
s.CheckGet(t, "VERSION:0:one", objectID)
|
||||
s.CheckGet(t, "VERSION:1:foo", objectID)
|
||||
s.CheckGet(t, "VERSION:1:bar", objectID)
|
||||
assert.Empty(t, s.HGet(objectID, "expiry"))
|
||||
assert.JSONEq(t, `{"ID":"one","Name":["foo","bar"]}`, s.HGet(objectID, "object"))
|
||||
assert.Positive(t, s.TTL(objectID))
|
||||
@@ -115,9 +115,9 @@ func Test_redisCache_set(t *testing.T) {
|
||||
},
|
||||
},
|
||||
assertions: func(t *testing.T, s *miniredis.Miniredis, objectID string) {
|
||||
s.CheckGet(t, "0:one", objectID)
|
||||
s.CheckGet(t, "1:foo", objectID)
|
||||
s.CheckGet(t, "1:bar", objectID)
|
||||
s.CheckGet(t, "VERSION:0:one", objectID)
|
||||
s.CheckGet(t, "VERSION:1:foo", objectID)
|
||||
s.CheckGet(t, "VERSION:1:bar", objectID)
|
||||
assert.NotEmpty(t, s.HGet(objectID, "expiry"))
|
||||
assert.JSONEq(t, `{"ID":"one","Name":["foo","bar"]}`, s.HGet(objectID, "object"))
|
||||
assert.Positive(t, s.TTL(objectID))
|
||||
@@ -141,9 +141,9 @@ func Test_redisCache_set(t *testing.T) {
|
||||
},
|
||||
},
|
||||
assertions: func(t *testing.T, s *miniredis.Miniredis, objectID string) {
|
||||
s.CheckGet(t, "0:one", objectID)
|
||||
s.CheckGet(t, "1:foo", objectID)
|
||||
s.CheckGet(t, "1:bar", objectID)
|
||||
s.CheckGet(t, "VERSION:0:one", objectID)
|
||||
s.CheckGet(t, "VERSION:1:foo", objectID)
|
||||
s.CheckGet(t, "VERSION:1:bar", objectID)
|
||||
assert.Empty(t, s.HGet(objectID, "expiry"))
|
||||
assert.JSONEq(t, `{"ID":"one","Name":["foo","bar"]}`, s.HGet(objectID, "object"))
|
||||
assert.Positive(t, s.TTL(objectID))
|
||||
@@ -710,7 +710,7 @@ func prepareCache(t *testing.T, conf cache.Config, options ...func(*Config)) (ca
|
||||
connector.Close()
|
||||
server.Close()
|
||||
})
|
||||
c := NewCache[testIndex, string, *testObject](conf, connector, testDB, testIndices)
|
||||
c := NewCache[testIndex, string, *testObject](conf, "VERSION", connector, testDB, testIndices)
|
||||
return c, server
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user