feat:(REQ-2699) 修改项目产品的缓存结构和定时job去刷新项目的产品

This commit is contained in:
lilong 2024-08-27 16:00:19 +08:00
parent cba58c9c63
commit 38e711217c
4 changed files with 115 additions and 29 deletions

View File

@ -32,6 +32,7 @@ import cn.axzo.tyr.server.job.CacheProductPermissionJob;
import cn.axzo.tyr.server.job.CacheRoleFeatureResourceJob; import cn.axzo.tyr.server.job.CacheRoleFeatureResourceJob;
import cn.axzo.tyr.server.job.CacheRolePermissionJob; import cn.axzo.tyr.server.job.CacheRolePermissionJob;
import cn.axzo.tyr.server.job.CacheSaasFeatureJob; import cn.axzo.tyr.server.job.CacheSaasFeatureJob;
import cn.axzo.tyr.server.job.CacheWorkspaceProductJob;
import cn.axzo.tyr.server.repository.dao.ProductModuleDao; import cn.axzo.tyr.server.repository.dao.ProductModuleDao;
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
@ -169,6 +170,8 @@ public class PrivateController {
private SaasRoleUserRelationService saasRoleUserRelationService; private SaasRoleUserRelationService saasRoleUserRelationService;
@Autowired @Autowired
private ProductModuleDao productModuleDao; private ProductModuleDao productModuleDao;
@Autowired
private CacheWorkspaceProductJob cacheWorkspaceProductJob;
/** /**
* 统一层级的roleGroup按照id升序sort从1递增 * 统一层级的roleGroup按照id升序sort从1递增
@ -623,12 +626,24 @@ public class PrivateController {
return featureCodeUtil.resolveFeatureCode(request.getFeatureCodes()); return featureCodeUtil.resolveFeatureCode(request.getFeatureCodes());
} }
@PostMapping("/api/private/workspaceProduct/store") @PostMapping("/api/private/productPermission/store")
public Object storeWorkspaceProduct(@RequestBody ProductSearchListReq request) throws Exception { public Object storeProductPermission(@RequestBody ProductSearchListReq request) throws Exception {
cacheProductPermissionJob.execute(JSON.toJSONString(request)); cacheProductPermissionJob.execute(JSON.toJSONString(request));
return "ok"; return "ok";
} }
@PostMapping("/api/private/workspaceProduct/store")
public Object storeWorkspaceProduct(@RequestBody WorkspaceProductService.StoreWorkspaceProductParam request) throws Exception {
workspaceProductService.storeWorkspaceProduct(request);
return "ok";
}
@PostMapping("/api/private/workspaceProduct/job")
public Object storeWorkspaceProductJob() throws Exception {
cacheWorkspaceProductJob.execute(null);
return "ok";
}
@PostMapping("/api/private/workspaceProduct/list") @PostMapping("/api/private/workspaceProduct/list")
public Object listWorkspaceProduct(@RequestBody WorkspaceProductService.WorkspaceProductParam request) { public Object listWorkspaceProduct(@RequestBody WorkspaceProductService.WorkspaceProductParam request) {
return workspaceProductService.listWorkspaceProductCached(request); return workspaceProductService.listWorkspaceProductCached(request);

View File

@ -0,0 +1,66 @@
package cn.axzo.tyr.server.job;
import cn.axzo.thrones.client.saas.ServicePkgClient;
import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct;
import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes;
import cn.axzo.tyr.server.service.WorkspaceProductService;
import cn.axzo.tyr.server.utils.RpcInternalUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@Slf4j
@Component
public class CacheWorkspaceProductJob extends IJobHandler {
@Autowired
private WorkspaceProductService workspaceProductService;
@Autowired
private ServicePkgClient servicePkgClient;
@Override
@XxlJob("CacheWorkspaceProductJob")
public ReturnT<String> execute(String s) throws Exception {
log.info("start CacheWorkspaceProductJob, s:{}", s);
// 全量更新所有项目的产品数量比较大所以这里只从缓存中的项目去更新产品
Map<Long, Set<Long>> allWorkspaceProducts = workspaceProductService.listAllWorkspaceProductCached();
Set<Long> workspaceIds = allWorkspaceProducts.keySet();
if (CollectionUtils.isEmpty(workspaceIds)) {
return ReturnT.SUCCESS;
}
List<ServicePkgDetailRes> servicePkgDetailRes = RpcInternalUtil.rpcListProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(workspaceIds),
"查询项目的产品", workspaceIds).getData();
List<WorkspaceProductService.WorkspaceProductDTO> workspaceProducts = servicePkgDetailRes.stream()
.map(e -> WorkspaceProductService.WorkspaceProductDTO.builder()
.workspaceId(e.getSpaceId())
.productIds(Optional.ofNullable(e.getProducts())
.map(products -> products.stream()
.map(ServicePkgProduct::getProductId)
.collect(Collectors.toSet()))
.orElse(null))
.build())
.collect(Collectors.toList());
WorkspaceProductService.StoreWorkspaceProductParam storeWorkspaceProductParam = WorkspaceProductService.StoreWorkspaceProductParam.builder()
.workspaceProducts(workspaceProducts)
.build();
workspaceProductService.storeWorkspaceProduct(storeWorkspaceProductParam);
return ReturnT.SUCCESS;
}
}

View File

@ -9,6 +9,7 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
public interface WorkspaceProductService { public interface WorkspaceProductService {
@ -43,6 +44,8 @@ public interface WorkspaceProductService {
*/ */
List<WorkspaceProductFeatureSource> listWorkspaceProductFeatureResourceCached(ListWorkspaceProductFeatureSourceCacheParam param); List<WorkspaceProductFeatureSource> listWorkspaceProductFeatureResourceCached(ListWorkspaceProductFeatureSourceCacheParam param);
Map<Long, Set<Long>> listAllWorkspaceProductCached();
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor

View File

@ -2,7 +2,7 @@ package cn.axzo.tyr.server.service.impl;
import cn.axzo.foundation.exception.Axssert; import cn.axzo.foundation.exception.Axssert;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.pokonyan.config.redis.RedisUtil; import cn.axzo.pokonyan.config.redis.RedisClient;
import cn.axzo.thrones.client.saas.ServicePkgClient; import cn.axzo.thrones.client.saas.ServicePkgClient;
import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct; import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct;
import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes; import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes;
@ -22,13 +22,9 @@ import com.google.common.collect.Sets;
import com.google.common.collect.Streams; import com.google.common.collect.Streams;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -37,6 +33,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -67,7 +64,7 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
@Value("${workspace.product.expire.minutes:14}") @Value("${workspace.product.expire.minutes:14}")
private Long expireInMinutes; private Long expireInMinutes;
private static final String WORKSPACE_PRODUCT_KEY = "workspace:product:%s"; private static final String WORKSPACE_PRODUCT_KEY = "workspace:product";
@Override @Override
public List<WorkspaceProduct> listWorkspaceProduct(WorkspaceProductParam param) { public List<WorkspaceProduct> listWorkspaceProduct(WorkspaceProductParam param) {
@ -184,35 +181,28 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
public void storeWorkspaceProduct(StoreWorkspaceProductParam param) { public void storeWorkspaceProduct(StoreWorkspaceProductParam param) {
Axssert.checkNotEmpty(param.getWorkspaceProducts(), REDIS_PRODUCT_NOT_NULL); Axssert.checkNotEmpty(param.getWorkspaceProducts(), REDIS_PRODUCT_NOT_NULL);
Map<String, String> redisValues = param.getWorkspaceProducts().stream()
redisTemplate.executePipelined(new SessionCallback<Object>() { .collect(Collectors.toMap(e -> e.getWorkspaceId().toString(), e -> Optional.ofNullable(e.getProductIds())
@Override .map(JSON::toJSONString)
public Object execute(RedisOperations operations) throws DataAccessException { .orElseGet(() -> JSON.toJSONString(Sets.newHashSet()))));
String redisKey = getKey();
for (WorkspaceProductDTO workspaceProduct : param.getWorkspaceProducts()) { RedisClient.HashOps.hPutAll(redisKey, redisValues);
String redisKey = getKey(workspaceProduct.getWorkspaceId()); redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES);
RedisUtil.StringValueOps.setEx(redisKey, JSON.toJSONString(workspaceProduct.getProductIds()), log.info("succeed to workspace product: redisKey:{} value:{}", redisKey, redisValues);
expireInMinutes, TimeUnit.MINUTES);
}
return null;
}
});
} }
private Map<Long, Set<Long>> listWorkspaceProduct(ListWorkspaceProductParam param) { private Map<Long, Set<Long>> listWorkspaceProduct(ListWorkspaceProductParam param) {
Axssert.checkNotEmpty(param.getWorkspaceIds(), WORKSPACE_ID_NOT_NULL); Axssert.checkNotEmpty(param.getWorkspaceIds(), WORKSPACE_ID_NOT_NULL);
List<String> redisKeys = param.getWorkspaceIds().stream() List<Object> redisValues = RedisClient.HashOps.hMultiGet(getKey(), param.getWorkspaceIds().stream()
.map(this::getKey) .map(String::valueOf)
.collect(Collectors.toList()); .collect(Collectors.toList()));
List<String> redisValues = redisTemplate.opsForValue().multiGet(redisKeys);
return Streams.zip(param.getWorkspaceIds().stream(), return Streams.zip(param.getWorkspaceIds().stream(),
redisValues.stream(), redisValues.stream(),
(workspaceId, redisValue) -> { (workspaceId, redisValue) -> {
if (StringUtils.isBlank(redisValue)) { if (Objects.isNull(redisValue)) {
return null; return null;
} }
@ -222,6 +212,7 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return Pair.of(workspaceId, productIds); return Pair.of(workspaceId, productIds);
}) })
.filter(Objects::nonNull) .filter(Objects::nonNull)
.collect(Collectors.toMap(Pair::getKey, Pair::getValue)); .collect(Collectors.toMap(Pair::getKey, Pair::getValue));
@ -275,8 +266,8 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
storeWorkspaceProduct(storeWorkspaceProductParam); storeWorkspaceProduct(storeWorkspaceProductParam);
} }
private String getKey(Object... params) { private String getKey() {
return String.format(WORKSPACE_PRODUCT_KEY, params); return String.format(WORKSPACE_PRODUCT_KEY);
} }
@Override @Override
@ -398,4 +389,15 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Override
public Map<Long, Set<Long>> listAllWorkspaceProductCached() {
return RedisClient.HashOps.hGetAll(getKey()).entrySet()
.stream()
.collect(Collectors.toMap(e -> Long.valueOf(e.getKey().toString()), e -> JSON.parseArray(e.getValue().toString())
.stream()
.map(productId -> Long.valueOf(productId.toString()))
.collect(Collectors.toSet())));
}
} }