Просмотр исходного кода

feat: token缓存逻辑更新(实验性)

CaIon 2 лет назад
Родитель
Сommit
ac3e27859c
4 измененных файлов с 83 добавлено и 18 удалено
  1. 5 0
      common/redis.go
  2. 3 0
      main.go
  3. 65 18
      model/cache.go
  4. 10 0
      model/token.go

+ 5 - 0
common/redis.go

@@ -57,6 +57,11 @@ func RedisGet(key string) (string, error) {
 	return RDB.Get(ctx, key).Result()
 	return RDB.Get(ctx, key).Result()
 }
 }
 
 
+func RedisGetEx(key string, expiration time.Duration) (string, error) {
+	ctx := context.Background()
+	return RDB.GetSet(ctx, key, expiration).Result()
+}
+
 func RedisDel(key string) error {
 func RedisDel(key string) error {
 	ctx := context.Background()
 	ctx := context.Background()
 	return RDB.Del(ctx, key).Err()
 	return RDB.Del(ctx, key).Err()

+ 3 - 0
main.go

@@ -63,6 +63,9 @@ func main() {
 		common.SysError(fmt.Sprintf("sync frequency: %d seconds", common.SyncFrequency))
 		common.SysError(fmt.Sprintf("sync frequency: %d seconds", common.SyncFrequency))
 		model.InitChannelCache()
 		model.InitChannelCache()
 	}
 	}
+	if common.RedisEnabled {
+		go model.SyncTokenCache(common.SyncFrequency)
+	}
 	if common.MemoryCacheEnabled {
 	if common.MemoryCacheEnabled {
 		go model.SyncOptions(common.SyncFrequency)
 		go model.SyncOptions(common.SyncFrequency)
 		go model.SyncChannelCache(common.SyncFrequency)
 		go model.SyncChannelCache(common.SyncFrequency)

+ 65 - 18
model/cache.go

@@ -20,34 +20,81 @@ var (
 	UserId2StatusCacheSeconds = common.SyncFrequency
 	UserId2StatusCacheSeconds = common.SyncFrequency
 )
 )
 
 
-func CacheGetTokenByKey(key string) (*Token, error) {
-	keyCol := "`key`"
-	if common.UsingPostgreSQL {
-		keyCol = `"key"`
+// 仅用于定时同步缓存
+var token2UserId = make(map[string]int)
+var token2UserIdLock sync.RWMutex
+
+func cacheSetToken(token *Token) error {
+	if !common.RedisEnabled {
+		return token.SelectUpdate()
 	}
 	}
-	var token Token
+	jsonBytes, err := json.Marshal(token)
+	if err != nil {
+		return err
+	}
+	err = common.RedisSet(fmt.Sprintf("token:%s", token.Key), string(jsonBytes), time.Duration(TokenCacheSeconds)*time.Second)
+	if err != nil {
+		common.SysError(fmt.Sprintf("failed to set token %s to redis: %s", token.Key, err.Error()))
+		return err
+	}
+	token2UserIdLock.Lock()
+	defer token2UserIdLock.Unlock()
+	token2UserId[token.Key] = token.UserId
+	return nil
+}
+
+// CacheGetTokenByKey 从缓存中获取 token 并续期时间,如果缓存中不存在,则从数据库中获取
+func CacheGetTokenByKey(key string) (*Token, error) {
 	if !common.RedisEnabled {
 	if !common.RedisEnabled {
-		err := DB.Where(keyCol+" = ?", key).First(&token).Error
-		return &token, err
+		return GetTokenByKey(key)
 	}
 	}
-	tokenObjectString, err := common.RedisGet(fmt.Sprintf("token:%s", key))
+	var token *Token
+	tokenObjectString, err := common.RedisGetEx(fmt.Sprintf("token:%s", key), time.Duration(TokenCacheSeconds)*time.Second)
 	if err != nil {
 	if err != nil {
-		err := DB.Where(keyCol+" = ?", key).First(&token).Error
+		// 如果缓存中不存在,则从数据库中获取
+		token, err = GetTokenByKey(key)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		jsonBytes, err := json.Marshal(token)
-		if err != nil {
-			return nil, err
+		err = cacheSetToken(token)
+		return token, nil
+	}
+	err = json.Unmarshal([]byte(tokenObjectString), &token)
+	return token, err
+}
+
+func SyncTokenCache(frequency int) {
+	for {
+		time.Sleep(time.Duration(frequency) * time.Second)
+		common.SysLog("syncing tokens from database")
+		token2UserIdLock.Lock()
+		// 从token2UserId中获取所有的key
+		var copyToken2UserId = make(map[string]int)
+		for s, i := range token2UserId {
+			copyToken2UserId[s] = i
 		}
 		}
-		err = common.RedisSet(fmt.Sprintf("token:%s", key), string(jsonBytes), time.Duration(TokenCacheSeconds)*time.Second)
-		if err != nil {
-			common.SysError("Redis set token error: " + err.Error())
+		token2UserId = make(map[string]int)
+		token2UserIdLock.Unlock()
+
+		for key := range copyToken2UserId {
+			token, err := GetTokenByKey(key)
+			if err != nil {
+				// 如果数据库中不存在,则删除缓存
+				common.SysError(fmt.Sprintf("failed to get token %s from database: %s", key, err.Error()))
+				//delete redis
+				err := common.RedisDel(fmt.Sprintf("token:%s", key))
+				if err != nil {
+					common.SysError(fmt.Sprintf("failed to delete token %s from redis: %s", key, err.Error()))
+				}
+			} else {
+				// 如果数据库中存在,则更新缓存
+				err := cacheSetToken(token)
+				if err != nil {
+					common.SysError(fmt.Sprintf("failed to update token %s to redis: %s", key, err.Error()))
+				}
+			}
 		}
 		}
-		return &token, nil
 	}
 	}
-	err = json.Unmarshal([]byte(tokenObjectString), &token)
-	return &token, err
 }
 }
 
 
 func CacheGetUserGroup(id int) (group string, err error) {
 func CacheGetUserGroup(id int) (group string, err error) {

+ 10 - 0
model/token.go

@@ -100,6 +100,16 @@ func GetTokenById(id int) (*Token, error) {
 	return &token, err
 	return &token, err
 }
 }
 
 
+func GetTokenByKey(key string) (*Token, error) {
+	keyCol := "`key`"
+	if common.UsingPostgreSQL {
+		keyCol = `"key"`
+	}
+	var token Token
+	err := DB.Where(keyCol+" = ?", key).First(&token).Error
+	return &token, err
+}
+
 func (token *Token) Insert() error {
 func (token *Token) Insert() error {
 	var err error
 	var err error
 	err = DB.Create(token).Error
 	err = DB.Create(token).Error