feat: sync privacy read-model rules
This commit is contained in:
parent
9f467f4be7
commit
5d5883a3d1
20 changed files with 1011 additions and 20 deletions
|
|
@ -207,6 +207,45 @@ func TestReadModelChangeListenerInvalidatesPrivateMediaCountCache(t *testing.T)
|
|||
}
|
||||
}
|
||||
|
||||
func TestReadModelChangeListenerInvalidatesAccountSettingsCache(t *testing.T) {
|
||||
settings := &fakeAccountSettingsReadModelCache{}
|
||||
listener := NewReadModelChangeListener("", ReadModelCacheSet{
|
||||
AccountSettings: settings,
|
||||
}, nil)
|
||||
|
||||
listener.handlePayload(`{"model":"account_settings","owner_user_id":100,"peer_type":"user","peer_id":100,"version":2}`)
|
||||
if len(settings.invalidated) != 1 || settings.invalidated[0] != 100 {
|
||||
t.Fatalf("account_settings invalidations = %v, want [100]", settings.invalidated)
|
||||
}
|
||||
if len(settings.warmed) != 1 || settings.warmed[0] != 100 {
|
||||
t.Fatalf("account_settings warmups = %v, want [100]", settings.warmed)
|
||||
}
|
||||
|
||||
listener.flush("test")
|
||||
if settings.flushes != 1 {
|
||||
t.Fatalf("account_settings flushes = %d, want 1", settings.flushes)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeAccountSettingsReadModelCache struct {
|
||||
invalidated []int64
|
||||
warmed []int64
|
||||
flushes int
|
||||
}
|
||||
|
||||
func (f *fakeAccountSettingsReadModelCache) InvalidateAccountSettingsReadModel(userID int64) {
|
||||
f.invalidated = append(f.invalidated, userID)
|
||||
}
|
||||
|
||||
func (f *fakeAccountSettingsReadModelCache) FlushAccountSettingsReadModel() {
|
||||
f.flushes++
|
||||
}
|
||||
|
||||
func (f *fakeAccountSettingsReadModelCache) WarmAccountSettingsReadModel(_ context.Context, userID int64) error {
|
||||
f.warmed = append(f.warmed, userID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestReadModelChangeListenerBotFullFlushesChannelFullBots 回归: bot 改资料(bot_full 事件,
|
||||
// 迁移 0013)须 flush channelFullBotInfoCache(否则群信息页 bot 简介/命令跨实例陈旧至 TTL);
|
||||
// 普通用户的 user_base 事件不得 flush(否则该缓存形同虚设)。
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ type ReadModelCacheSet struct {
|
|||
BaseUsers BaseUserCache
|
||||
BotProfiles BotProfileReadModelCache
|
||||
StarGifts StarGiftCatalogCache
|
||||
AccountSettings AccountSettingsReadModelCache
|
||||
}
|
||||
|
||||
type StarGiftCatalogCache interface {
|
||||
|
|
@ -44,6 +45,15 @@ type StarGiftCatalogCache interface {
|
|||
FlushStarGiftCatalog()
|
||||
}
|
||||
|
||||
type AccountSettingsReadModelCache interface {
|
||||
InvalidateAccountSettingsReadModel(userID int64)
|
||||
FlushAccountSettingsReadModel()
|
||||
}
|
||||
|
||||
type AccountSettingsReadModelWarmer interface {
|
||||
WarmAccountSettingsReadModel(context.Context, int64) error
|
||||
}
|
||||
|
||||
// BaseUserCache 是跨进程共享的 user:base 缓存(Redis)。user_base read-model 事件必须删除
|
||||
// 对应 user 键,否则 RPC 投影失效后会从陈旧的 user:base 重建(失效被未失效的源自我抵消)。
|
||||
// 不参与重连 flush:Redis 是跨实例共享的,整库清空是错的,漏掉的通知靠其自身 TTL 兜底。
|
||||
|
|
@ -241,7 +251,8 @@ func (l *ReadModelChangeListener) empty() bool {
|
|||
l.caches.RPCProjections == nil &&
|
||||
l.caches.BaseUsers == nil &&
|
||||
l.caches.BotProfiles == nil &&
|
||||
l.caches.StarGifts == nil
|
||||
l.caches.StarGifts == nil &&
|
||||
l.caches.AccountSettings == nil
|
||||
}
|
||||
|
||||
func (l *ReadModelChangeListener) flush(reasons ...string) {
|
||||
|
|
@ -318,6 +329,10 @@ func (l *ReadModelChangeListener) flush(reasons ...string) {
|
|||
l.caches.StarGifts.FlushStarGiftCatalog()
|
||||
flushed = append(flushed, "star_gifts")
|
||||
}
|
||||
if l.caches.AccountSettings != nil {
|
||||
l.caches.AccountSettings.FlushAccountSettingsReadModel()
|
||||
flushed = append(flushed, "account_settings")
|
||||
}
|
||||
// 注意:BaseUsers(Redis) 刻意不在重连时 flush——它是跨实例共享缓存,整库清空会误伤
|
||||
// 其它实例;漏掉的通知由其 5min TTL 兜底。
|
||||
l.log.Info("read model caches flushed",
|
||||
|
|
@ -346,6 +361,19 @@ func (l *ReadModelChangeListener) handlePayload(payload string) {
|
|||
}
|
||||
}
|
||||
switch evt.Model {
|
||||
case "account_settings":
|
||||
if evt.OwnerUserID != 0 && l.caches.AccountSettings != nil {
|
||||
l.caches.AccountSettings.InvalidateAccountSettingsReadModel(evt.OwnerUserID)
|
||||
if warmer, ok := l.caches.AccountSettings.(AccountSettingsReadModelWarmer); ok {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), privacyReadModelWarmTimeout)
|
||||
err := warmer.WarmAccountSettingsReadModel(ctx, evt.OwnerUserID)
|
||||
cancel()
|
||||
if err != nil {
|
||||
l.log.Warn("warm account settings read model after change",
|
||||
zap.Int64("owner_user_id", evt.OwnerUserID), zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
case "star_gift_catalog":
|
||||
if l.caches.StarGifts != nil {
|
||||
l.caches.StarGifts.InvalidateStarGiftCatalog()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue