fix(facade,manager): harden grpc calls and add bulk lookups

This commit is contained in:
pnoker
2026-05-09 16:18:31 +08:00
parent 0434d5b033
commit df06264f9c
15 changed files with 220 additions and 35 deletions
@@ -41,6 +41,8 @@ service DeviceApi {
rpc SelectByDriverId (GrpcDriverQuery) returns (GrpcRDeviceListDTO);
// Query single device information by Device ID
rpc SelectByDeviceId (GrpcDeviceQuery) returns (GrpcRDeviceDTO);
// Batch query device information by Device IDs
rpc SelectByDeviceIds (GrpcDeviceIdsQuery) returns (GrpcRDeviceListDTO);
}
// Response wrapper for paginated device query
@@ -77,4 +79,4 @@ message GrpcRDeviceDTO {
// Returned single device data
GrpcDeviceDTO data = 2;
}
}
@@ -37,6 +37,8 @@ service DriverApi {
rpc SelectByPage (GrpcPageDriverQuery) returns (GrpcRPageDriverDTO);
// Query driver information by Driver ID
rpc SelectByDriverId (GrpcDriverQuery) returns (GrpcRDriverDTO);
// Batch query driver information by Driver IDs
rpc SelectByDriverIds (GrpcDriverIdsQuery) returns (GrpcRDriverListDTO);
// Query associated driver information by Device ID
rpc SelectByDeviceId (GrpcDeviceQuery) returns (GrpcRDriverDTO);
}
@@ -59,6 +61,15 @@ message GrpcPageDriverDTO {
repeated GrpcDriverDTO data = 2;
}
// Response wrapper for driver list query
message GrpcRDriverListDTO {
// Common result wrapper containing status code, message, etc.
GrpcR result = 1;
// Returned driver list data
repeated GrpcDriverDTO data = 2;
}
// Response wrapper for single driver query
message GrpcRDriverDTO {
// Common result wrapper containing status code, message, etc.
@@ -37,6 +37,8 @@ service PointApi {
rpc SelectByPage (GrpcPagePointQuery) returns (GrpcRPagePointDTO);
// Query single point information by point ID
rpc SelectById (GrpcPointQuery) returns (GrpcRPointDTO);
// Batch query point information by point IDs
rpc SelectByIds (GrpcPointIdsQuery) returns (GrpcRPointListDTO);
}
// Response wrapper for paginated point query
@@ -57,6 +59,15 @@ message GrpcPagePointDTO {
repeated GrpcPointDTO data = 2;
}
// Response wrapper for point list query
message GrpcRPointListDTO {
// Common result wrapper containing status code, message, etc.
GrpcR result = 1;
// Returned point list data
repeated GrpcPointDTO data = 2;
}
// Response wrapper for single point query
message GrpcRPointDTO {
// Common result wrapper containing status code, message, etc.
@@ -65,4 +76,3 @@ message GrpcRPointDTO {
// Returned single point data
GrpcPointDTO data = 2;
}
@@ -31,6 +31,12 @@ message GrpcDriverQuery {
int64 driver_id = 1;
}
// Driver ids query structure for batch driver lookup
message GrpcDriverIdsQuery {
// Identifies driver instances
repeated int64 driver_ids = 1;
}
// Profile template query structure for querying template information by profile ID
message GrpcProfileQuery {
// Profile template ID that identifies specific configuration template
@@ -43,11 +49,22 @@ message GrpcPointQuery {
int64 point_id = 1;
}
// Point ids query structure for batch point lookup
message GrpcPointIdsQuery {
// Identifies point instances
repeated int64 point_ids = 1;
}
// Device query structure for querying device information by device ID
message GrpcDeviceQuery {
// Device ID that identifies specific device
int64 device_id = 1;
}
// Device ids query structure for batch device lookup
message GrpcDeviceIdsQuery {
// Identifies device instances
repeated int64 device_ids = 1;
}
@@ -56,10 +56,14 @@ public class DeviceGrpcFacade implements DeviceFacade {
@Resource
private FacadeGrpcDeviceBuilder facadeGrpcDeviceBuilder;
@Resource
private GrpcFacadeSupport grpcFacadeSupport;
@Override
public FacadeDeviceBO selectById(Long id) {
GrpcDeviceQuery request = GrpcDeviceQuery.newBuilder().setDeviceId(id).build();
GrpcRDeviceDTO response = deviceApiBlockingStub.selectByDeviceId(request);
GrpcRDeviceDTO response = grpcFacadeSupport.call("DeviceFacade.selectById", deviceApiBlockingStub,
stub -> stub.selectByDeviceId(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectById");
return null;
@@ -67,23 +71,31 @@ public class DeviceGrpcFacade implements DeviceFacade {
return facadeGrpcDeviceBuilder.toFacadeBO(response.getData());
}
/**
* Manager doesn't (yet) expose a batch RPC, so we fan out to {@link #selectById}
* concurrently. This collapses N round-trip latencies into roughly one. When
* call-volume justifies it, replace with a server-side batch RPC.
*/
@Override
public List<FacadeDeviceBO> selectByIds(Collection<Long> ids) {
if (Objects.isNull(ids) || ids.isEmpty()) {
return Collections.emptyList();
}
return ids.parallelStream().distinct().map(this::selectById).filter(Objects::nonNull).toList();
List<Long> deviceIds = ids.stream().filter(Objects::nonNull).distinct().toList();
if (deviceIds.isEmpty()) {
return Collections.emptyList();
}
GrpcDeviceIdsQuery request = GrpcDeviceIdsQuery.newBuilder().addAllDeviceIds(deviceIds).build();
GrpcRDeviceListDTO response = grpcFacadeSupport.call("DeviceFacade.selectByIds", deviceApiBlockingStub,
stub -> stub.selectByDeviceIds(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectByIds");
return Collections.emptyList();
}
return response.getDataList().stream().map(facadeGrpcDeviceBuilder::toFacadeBO).toList();
}
@Override
public FacadePage<FacadeDeviceBO> selectByPage(FacadeDeviceQuery query) {
GrpcPageDeviceQuery request = facadeGrpcDeviceBuilder.toGrpcPageQuery(query);
GrpcRPageDeviceDTO response = deviceApiBlockingStub.selectByPage(request);
GrpcRPageDeviceDTO response = grpcFacadeSupport.call("DeviceFacade.selectByPage", deviceApiBlockingStub,
stub -> stub.selectByPage(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectByPage");
return FacadePage.empty();
@@ -99,7 +111,8 @@ public class DeviceGrpcFacade implements DeviceFacade {
@Override
public List<FacadeDeviceBO> selectByProfileId(Long profileId) {
GrpcProfileQuery request = GrpcProfileQuery.newBuilder().setProfileId(profileId).build();
GrpcRDeviceListDTO response = deviceApiBlockingStub.selectByProfileId(request);
GrpcRDeviceListDTO response = grpcFacadeSupport.call("DeviceFacade.selectByProfileId", deviceApiBlockingStub,
stub -> stub.selectByProfileId(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectByProfileId");
return Collections.emptyList();
@@ -110,7 +123,8 @@ public class DeviceGrpcFacade implements DeviceFacade {
@Override
public List<FacadeDeviceBO> selectByDriverId(Long driverId) {
GrpcDriverQuery request = GrpcDriverQuery.newBuilder().setDriverId(driverId).build();
GrpcRDeviceListDTO response = deviceApiBlockingStub.selectByDriverId(request);
GrpcRDeviceListDTO response = grpcFacadeSupport.call("DeviceFacade.selectByDriverId", deviceApiBlockingStub,
stub -> stub.selectByDriverId(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectByDriverId");
return Collections.emptyList();
@@ -53,10 +53,14 @@ public class DriverGrpcFacade implements DriverFacade {
@Resource
private FacadeGrpcDriverBuilder facadeGrpcDriverBuilder;
@Resource
private GrpcFacadeSupport grpcFacadeSupport;
@Override
public FacadeDriverBO selectById(Long id) {
GrpcDriverQuery request = GrpcDriverQuery.newBuilder().setDriverId(id).build();
GrpcRDriverDTO response = driverApiBlockingStub.selectByDriverId(request);
GrpcRDriverDTO response = grpcFacadeSupport.call("DriverFacade.selectById", driverApiBlockingStub,
stub -> stub.selectByDriverId(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectById");
return null;
@@ -64,23 +68,31 @@ public class DriverGrpcFacade implements DriverFacade {
return facadeGrpcDriverBuilder.toFacadeBO(response.getData());
}
/**
* Manager doesn't (yet) expose a batch RPC, so we fan out to {@link #selectById}
* concurrently. This collapses N round-trip latencies into roughly one. When
* call-volume justifies it, replace with a server-side batch RPC.
*/
@Override
public List<FacadeDriverBO> selectByIds(Collection<Long> ids) {
if (Objects.isNull(ids) || ids.isEmpty()) {
return Collections.emptyList();
}
return ids.parallelStream().distinct().map(this::selectById).filter(Objects::nonNull).toList();
List<Long> driverIds = ids.stream().filter(Objects::nonNull).distinct().toList();
if (driverIds.isEmpty()) {
return Collections.emptyList();
}
GrpcDriverIdsQuery request = GrpcDriverIdsQuery.newBuilder().addAllDriverIds(driverIds).build();
GrpcRDriverListDTO response = grpcFacadeSupport.call("DriverFacade.selectByIds", driverApiBlockingStub,
stub -> stub.selectByDriverIds(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectByIds");
return Collections.emptyList();
}
return response.getDataList().stream().map(facadeGrpcDriverBuilder::toFacadeBO).toList();
}
@Override
public FacadePage<FacadeDriverBO> selectByPage(FacadeDriverQuery query) {
GrpcPageDriverQuery request = facadeGrpcDriverBuilder.toGrpcPageQuery(query);
GrpcRPageDriverDTO response = driverApiBlockingStub.selectByPage(request);
GrpcRPageDriverDTO response = grpcFacadeSupport.call("DriverFacade.selectByPage", driverApiBlockingStub,
stub -> stub.selectByPage(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectByPage");
return FacadePage.empty();
@@ -96,7 +108,8 @@ public class DriverGrpcFacade implements DriverFacade {
@Override
public FacadeDriverBO selectByDeviceId(Long deviceId) {
GrpcDeviceQuery request = GrpcDeviceQuery.newBuilder().setDeviceId(deviceId).build();
GrpcRDriverDTO response = driverApiBlockingStub.selectByDeviceId(request);
GrpcRDriverDTO response = grpcFacadeSupport.call("DriverFacade.selectByDeviceId", driverApiBlockingStub,
stub -> stub.selectByDeviceId(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectByDeviceId");
return null;
@@ -53,10 +53,14 @@ public class PointGrpcFacade implements PointFacade {
@Resource
private FacadeGrpcPointBuilder facadeGrpcPointBuilder;
@Resource
private GrpcFacadeSupport grpcFacadeSupport;
@Override
public FacadePointBO selectById(Long id) {
GrpcPointQuery request = GrpcPointQuery.newBuilder().setPointId(id).build();
GrpcRPointDTO response = pointApiBlockingStub.selectById(request);
GrpcRPointDTO response = grpcFacadeSupport.call("PointFacade.selectById", pointApiBlockingStub,
stub -> stub.selectById(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectById");
return null;
@@ -64,23 +68,31 @@ public class PointGrpcFacade implements PointFacade {
return facadeGrpcPointBuilder.toFacadeBO(response.getData());
}
/**
* Manager doesn't (yet) expose a batch RPC, so we fan out to {@link #selectById}
* concurrently. This collapses N round-trip latencies into roughly one. When
* call-volume justifies it, replace with a server-side batch RPC.
*/
@Override
public List<FacadePointBO> selectByIds(Collection<Long> ids) {
if (Objects.isNull(ids) || ids.isEmpty()) {
return Collections.emptyList();
}
return ids.parallelStream().distinct().map(this::selectById).filter(Objects::nonNull).toList();
List<Long> pointIds = ids.stream().filter(Objects::nonNull).distinct().toList();
if (pointIds.isEmpty()) {
return Collections.emptyList();
}
GrpcPointIdsQuery request = GrpcPointIdsQuery.newBuilder().addAllPointIds(pointIds).build();
GrpcRPointListDTO response = grpcFacadeSupport.call("PointFacade.selectByIds", pointApiBlockingStub,
stub -> stub.selectByIds(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectByIds");
return Collections.emptyList();
}
return response.getDataList().stream().map(facadeGrpcPointBuilder::toFacadeBO).toList();
}
@Override
public FacadePage<FacadePointBO> selectByPage(FacadePointQuery query) {
GrpcPagePointQuery request = facadeGrpcPointBuilder.toGrpcPageQuery(query);
GrpcRPagePointDTO response = pointApiBlockingStub.selectByPage(request);
GrpcRPagePointDTO response = grpcFacadeSupport.call("PointFacade.selectByPage", pointApiBlockingStub,
stub -> stub.selectByPage(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectByPage");
return FacadePage.empty();
@@ -47,6 +47,9 @@ public class ResourceRegistryGrpcFacade implements ResourceRegistryFacade {
@Resource
private ResourceRegistryApiGrpc.ResourceRegistryApiBlockingStub resourceRegistryApiBlockingStub;
@Resource
private GrpcFacadeSupport grpcFacadeSupport;
@Override
public FacadeResourceRegistrySyncResultBO sync(FacadeResourceRegistrySyncCommandBO command) {
GrpcSyncRequest.Builder request = GrpcSyncRequest.newBuilder()
@@ -65,7 +68,9 @@ public class ResourceRegistryGrpcFacade implements ResourceRegistryFacade {
.build());
}
}
GrpcRSyncResult response = resourceRegistryApiBlockingStub.sync(request.build());
GrpcSyncRequest syncRequest = request.build();
GrpcRSyncResult response = grpcFacadeSupport.call("ResourceRegistryFacade.sync", resourceRegistryApiBlockingStub,
stub -> stub.sync(syncRequest));
if (!response.getResult().getOk()) {
throw new ServiceException("ResourceRegistryFacade.sync failed: [" + response.getResult().getCode() + "] "
+ response.getResult().getMessage());
@@ -47,9 +47,14 @@ public class TenantGrpcFacade implements TenantFacade {
@Resource
private FacadeGrpcTenantBuilder facadeGrpcTenantBuilder;
@Resource
private GrpcFacadeSupport grpcFacadeSupport;
@Override
public FacadeTenantBO selectByCode(String code) {
GrpcRTenantDTO response = tenantApiBlockingStub.selectByCode(GrpcCodeQuery.newBuilder().setCode(code).build());
GrpcCodeQuery request = GrpcCodeQuery.newBuilder().setCode(code).build();
GrpcRTenantDTO response = grpcFacadeSupport.call("TenantFacade.selectByCode", tenantApiBlockingStub,
stub -> stub.selectByCode(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectByCode");
return null;
@@ -39,6 +39,9 @@ public class TokenGrpcFacade implements TokenFacade {
@Resource
private TokenApiGrpc.TokenApiBlockingStub tokenApiBlockingStub;
@Resource
private GrpcFacadeSupport grpcFacadeSupport;
@Override
public boolean checkValid(String tenant, String name, String salt, String token) {
GrpcLoginQuery login = GrpcLoginQuery.newBuilder()
@@ -47,7 +50,8 @@ public class TokenGrpcFacade implements TokenFacade {
.setSalt(salt)
.setToken(token)
.build();
GrpcRTokenDTO response = tokenApiBlockingStub.checkValid(login);
GrpcRTokenDTO response = grpcFacadeSupport.call("TokenFacade.checkValid", tokenApiBlockingStub,
stub -> stub.checkValid(login));
return response.getResult().getOk();
}
@@ -47,9 +47,14 @@ public class UserGrpcFacade implements UserFacade {
@Resource
private FacadeGrpcUserBuilder facadeGrpcUserBuilder;
@Resource
private GrpcFacadeSupport grpcFacadeSupport;
@Override
public FacadeUserBO selectById(Long id) {
GrpcRUserDTO response = userApiBlockingStub.selectById(GrpcIdQuery.newBuilder().setId(id).build());
GrpcIdQuery request = GrpcIdQuery.newBuilder().setId(id).build();
GrpcRUserDTO response = grpcFacadeSupport.call("UserFacade.selectById", userApiBlockingStub,
stub -> stub.selectById(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectById");
return null;
@@ -47,10 +47,14 @@ public class UserLoginGrpcFacade implements UserLoginFacade {
@Resource
private FacadeGrpcUserLoginBuilder facadeGrpcUserLoginBuilder;
@Resource
private GrpcFacadeSupport grpcFacadeSupport;
@Override
public FacadeUserLoginBO selectByName(String name) {
GrpcRUserLoginDTO response = userLoginApiBlockingStub
.selectByName(GrpcNameQuery.newBuilder().setName(name).build());
GrpcNameQuery request = GrpcNameQuery.newBuilder().setName(name).build();
GrpcRUserLoginDTO response = grpcFacadeSupport.call("UserLoginFacade.selectByName", userLoginApiBlockingStub,
stub -> stub.selectByName(request));
if (!response.getResult().getOk()) {
guardOrThrow(response.getResult(), "selectByName");
return null;
@@ -146,6 +146,33 @@ public class ManagerDeviceServer extends DeviceApiGrpc.DeviceApiImplBase {
responseObserver.onCompleted();
}
@Override
public void selectByDeviceIds(GrpcDeviceIdsQuery request, StreamObserver<GrpcRDeviceListDTO> responseObserver) {
GrpcRDeviceListDTO.Builder builder = GrpcRDeviceListDTO.newBuilder();
GrpcR.Builder rBuilder = GrpcR.newBuilder();
List<DeviceBO> entityBOList = deviceService.selectByIds(request.getDeviceIdsList().stream().distinct().toList());
if (CollectionUtils.isEmpty(entityBOList)) {
rBuilder.setOk(false);
rBuilder.setCode(ResponseEnum.NO_RESOURCE.getCode());
rBuilder.setMessage(ResponseEnum.NO_RESOURCE.getText());
} else {
rBuilder.setOk(true);
rBuilder.setCode(ResponseEnum.OK.getCode());
rBuilder.setMessage(ResponseEnum.OK.getText());
List<GrpcDeviceDTO> entityGrpcDTOList = entityBOList.stream()
.map(grpcDeviceBuilder::buildGrpcDTOByBO)
.toList();
builder.addAllData(entityGrpcDTOList);
}
builder.setResult(rBuilder);
responseObserver.onNext(builder.build());
responseObserver.onCompleted();
}
@Override
public void selectByDeviceId(GrpcDeviceQuery request, StreamObserver<GrpcRDeviceDTO> responseObserver) {
GrpcRDeviceDTO.Builder builder = GrpcRDeviceDTO.newBuilder();
@@ -32,6 +32,7 @@ import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -114,6 +115,33 @@ public class ManagerDriverServer extends DriverApiGrpc.DriverApiImplBase {
responseObserver.onCompleted();
}
@Override
public void selectByDriverIds(GrpcDriverIdsQuery request, StreamObserver<GrpcRDriverListDTO> responseObserver) {
GrpcRDriverListDTO.Builder builder = GrpcRDriverListDTO.newBuilder();
GrpcR.Builder rBuilder = GrpcR.newBuilder();
List<DriverBO> entityBOList = driverService.selectByIds(new HashSet<>(request.getDriverIdsList()));
if (Objects.isNull(entityBOList) || entityBOList.isEmpty()) {
rBuilder.setOk(false);
rBuilder.setCode(ResponseEnum.NO_RESOURCE.getCode());
rBuilder.setMessage(ResponseEnum.NO_RESOURCE.getText());
} else {
rBuilder.setOk(true);
rBuilder.setCode(ResponseEnum.OK.getCode());
rBuilder.setMessage(ResponseEnum.OK.getText());
List<GrpcDriverDTO> entityGrpcDTOList = entityBOList.stream()
.map(grpcDriverBuilder::buildGrpcDTOByBO)
.toList();
builder.addAllData(entityGrpcDTOList);
}
builder.setResult(rBuilder);
responseObserver.onNext(builder.build());
responseObserver.onCompleted();
}
@Override
public void selectByDriverId(GrpcDriverQuery request, StreamObserver<GrpcRDriverDTO> responseObserver) {
GrpcRDriverDTO.Builder builder = GrpcRDriverDTO.newBuilder();
@@ -32,6 +32,7 @@ import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -91,6 +92,33 @@ public class ManagerPointServer extends PointApiGrpc.PointApiImplBase {
responseObserver.onCompleted();
}
@Override
public void selectByIds(GrpcPointIdsQuery request, StreamObserver<GrpcRPointListDTO> responseObserver) {
GrpcRPointListDTO.Builder builder = GrpcRPointListDTO.newBuilder();
GrpcR.Builder rBuilder = GrpcR.newBuilder();
List<PointBO> entityBOList = pointService.selectByIds(new HashSet<>(request.getPointIdsList()));
if (Objects.isNull(entityBOList) || entityBOList.isEmpty()) {
rBuilder.setOk(false);
rBuilder.setCode(ResponseEnum.NO_RESOURCE.getCode());
rBuilder.setMessage(ResponseEnum.NO_RESOURCE.getText());
} else {
rBuilder.setOk(true);
rBuilder.setCode(ResponseEnum.OK.getCode());
rBuilder.setMessage(ResponseEnum.OK.getText());
List<GrpcPointDTO> entityGrpcDTOList = entityBOList.stream()
.map(grpcPointBuilder::buildGrpcDTOByBO)
.toList();
builder.addAllData(entityGrpcDTOList);
}
builder.setResult(rBuilder);
responseObserver.onNext(builder.build());
responseObserver.onCompleted();
}
@Override
public void selectById(GrpcPointQuery request, StreamObserver<GrpcRPointDTO> responseObserver) {
GrpcRPointDTO.Builder builder = GrpcRPointDTO.newBuilder();