feat(liveforum): add WebAPI Redis cache management for streamer flower counts
All checks were successful
continuous-integration/drone/push Build is passing

- Add WebApiCache Redis client instance to RedisServer for separate cache storage
- Configure WebApiCache in appsettings.json with dedicated database (db=2)
- Add ClearAllFlowerCache() method to IT_StreamersService interface and implementation
- Add clear-flower-cache endpoint in T_StreamersController with permission and logging
- Update flower cache operations to use WebApiCache instead of main Cache instance
- Migrate existing cache clear logic in UpdateStreamer and BatchSetFlowerCount to use WebApiCache
- Add clearFlowerCache API function to frontend tstreamers.js
- Add clear cache button to tstreamers.vue UI for manual cache management
- Improves cache isolation between admin and WebAPI services, enabling independent cache lifecycle management
This commit is contained in:
zpc 2026-04-01 18:28:28 +08:00
parent 70c1654a96
commit c227256015
7 changed files with 94 additions and 9 deletions

View File

@ -7,11 +7,17 @@ namespace ZR.Common.Cache
{
public static CSRedisClient Cache;
public static CSRedisClient Session;
public static CSRedisClient WebApiCache;
public static void Initalize()
{
Cache = new CSRedisClient(AppSettings.GetConfig("RedisServer:Cache"));
Session = new CSRedisClient(AppSettings.GetConfig("RedisServer:Session"));
var webApiCacheConfig = AppSettings.GetConfig("RedisServer:WebApiCache");
if (!string.IsNullOrEmpty(webApiCacheConfig))
{
WebApiCache = new CSRedisClient(webApiCacheConfig);
}
}
}
}

View File

@ -168,5 +168,25 @@ namespace ZR.Admin.WebApi.Controllers.Liveforum
return ToResponse(result);
}
/// <summary>
/// 清空所有主播送花缓存
/// </summary>
/// <returns></returns>
[HttpPost("clear-flower-cache")]
[ActionPermissionFilter(Permission = "tstreamers:edit")]
[Log(Title = "清空送花缓存", BusinessType = BusinessType.OTHER)]
public IActionResult ClearFlowerCache()
{
try
{
var count = _T_StreamersService.ClearAllFlowerCache();
return SUCCESS(new { clearedCount = count, message = $"成功清除 {count} 个送花缓存" });
}
catch (Exception ex)
{
throw new CustomException(ResultCode.CUSTOM_ERROR, $"清除缓存失败:{ex.Message}");
}
}
}
}

View File

@ -109,7 +109,8 @@
"open": 1, //redis
"dbCache": false, //使Redisopen1
"Cache": "192.168.195.15:6379,defaultDatabase=6,poolsize=50,ssl=false,writeBuffer=10240,prefix=cache:",
"Session": "192.168.195.15:6379,defaultDatabase=7,poolsize=50,ssl=false,writeBuffer=10240,prefix=session:"
"Session": "192.168.195.15:6379,defaultDatabase=7,poolsize=50,ssl=false,writeBuffer=10240,prefix=session:",
"WebApiCache": "192.168.195.15:6379,defaultDatabase=2,poolsize=10,ssl=false,writeBuffer=10240"
},
//
"CaptchaOptions": {

View File

@ -39,5 +39,11 @@ namespace ZR.Service.Liveforum.ILiveforumService
/// <param name="setAll">是否设置所有主播</param>
/// <returns></returns>
int BatchSetFlowerCount(int[]? ids, int minFlowerCount, int maxFlowerCount, bool setAll = false);
/// <summary>
/// 清空所有主播的送花缓存
/// </summary>
/// <returns>清除的缓存key数量</returns>
int ClearAllFlowerCache();
}
}

View File

@ -75,14 +75,14 @@ namespace ZR.Service.Liveforum
{
var result = Update(model, true);
// 清除该主播的Redis花数缓存
// 清除该主播在WebAPI Redis中的花数缓存
try
{
RedisServer.Cache.Del($"flower_count:Streamer:{model.Id}");
RedisServer.WebApiCache?.Del($"flower_count:Streamer:{model.Id}");
}
catch (Exception ex)
{
NLog.LogManager.GetCurrentClassLogger().Warn(ex, "清除Redis花数缓存失败, StreamerId: {0}", model.Id);
NLog.LogManager.GetCurrentClassLogger().Warn(ex, "清除WebAPI Redis花数缓存失败, StreamerId: {0}", model.Id);
}
return result;
@ -139,24 +139,44 @@ namespace ZR.Service.Liveforum
.UpdateColumns(it => new { it.FlowerCount, it.UpdatedAt })
.ExecuteCommand();
// 清除Redis中对应主播的花数缓存确保WebAPI读取最新数据
// 清除WebAPI Redis中对应主播的花数缓存
try
{
foreach (var streamer in streamers)
{
var cacheKey = $"flower_count:Streamer:{streamer.Id}";
RedisServer.Cache.Del(cacheKey);
RedisServer.WebApiCache?.Del(cacheKey);
}
}
catch (Exception ex)
{
// Redis清除失败不影响主流程缓存会在24小时后自动过期
NLog.LogManager.GetCurrentClassLogger().Warn(ex, "清除Redis花数缓存失败");
NLog.LogManager.GetCurrentClassLogger().Warn(ex, "清除WebAPI Redis花数缓存失败");
}
return result;
}
/// <summary>
/// 清空所有主播的送花缓存WebAPI Redis
/// </summary>
/// <returns>清除的缓存key数量</returns>
public int ClearAllFlowerCache()
{
if (RedisServer.WebApiCache == null)
{
throw new Exception("WebAPI Redis未配置请检查appsettings.json中的RedisServer:WebApiCache配置");
}
var keys = RedisServer.WebApiCache.Keys("flower_count:Streamer:*");
if (keys == null || keys.Length == 0)
{
return 0;
}
RedisServer.WebApiCache.Del(keys);
return keys.Length;
}
/// <summary>
/// 查询导出表达式
/// </summary>

View File

@ -91,3 +91,13 @@ export function batchSetFlowerCount(data) {
data: data
})
}
/**
* 清空所有主播送花缓存
*/
export function clearFlowerCache() {
return request({
url: 'liveforum/tstreamers/clear-flower-cache',
method: 'POST'
})
}

View File

@ -53,6 +53,11 @@
批量设置送花数量
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" v-hasPermi="['tstreamers:edit']" plain icon="delete" @click="handleClearFlowerCache">
清空送花缓存
</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
@ -291,7 +296,7 @@
</template>
<script setup name="tstreamers">
import { listtstreamers, addtstreamers, deltstreamers, updatetstreamers, gettstreamers, batchDisableStreamers, batchEnableStreamers, batchSetFlowerCount } from '@/api/liveforum/tstreamers.js'
import { listtstreamers, addtstreamers, deltstreamers, updatetstreamers, gettstreamers, batchDisableStreamers, batchEnableStreamers, batchSetFlowerCount, clearFlowerCache } from '@/api/liveforum/tstreamers.js'
const { proxy } = getCurrentInstance()
const ids = ref([])
const loading = ref(false)
@ -821,5 +826,22 @@ function submitBatchFlower() {
})
}
//
function handleClearFlowerCache() {
proxy
.$confirm('确认清空所有主播的送花缓存吗?清空后小程序将从数据库重新读取送花数量。', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
return clearFlowerCache()
})
.then((res) => {
proxy.$modal.msgSuccess(res.data?.message || '清空送花缓存成功')
})
.catch(() => {})
}
handleQuery()
</script>