diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java b/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java index f15fc2e0..afedbb4b 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java @@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.inference; import com.kamco.cd.kamcoback.config.api.ApiResponseDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; +import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.ResultList; import com.kamco.cd.kamcoback.inference.service.InferenceResultService; import com.kamco.cd.kamcoback.mapsheet.service.MapSheetMngService; @@ -217,4 +218,23 @@ public class InferenceResultApiController { // inferenceResultService.getInferenceResultGeomList(id, searchGeoReq); // return ApiResponseDto.ok(geomList); // } + + @Operation(summary = "추론관리 추론진행 서버 현황", description = "추론관리 추론진행 서버 현황") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "검색 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Page.class))), + @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/serverStatus") + public ApiResponseDto> getInferenceServerStatusList() { + + return ApiResponseDto.ok(inferenceResultService.getInferenceServerStatusList()); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceResultDto.java b/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceResultDto.java index bad92295..3941876f 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceResultDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceResultDto.java @@ -1,5 +1,6 @@ package com.kamco.cd.kamcoback.inference.dto; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.kamco.cd.kamcoback.common.utils.enums.EnumType; import com.kamco.cd.kamcoback.common.utils.interfaces.EnumValid; @@ -196,4 +197,107 @@ public class InferenceResultDto { private String mapSheetNum; private String mapSheetName; } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class InferenceServerStatusDto { + + private String serverName; + @JsonIgnore + private float cpu_user; + @JsonIgnore private float cpu_system; + @JsonIgnore private float memused; + private Long kbmemused; + private float gpuUtil; + //private String cpuStatusName; + //private String memStatusName; + //private String gpuStatusName; + //private float cpu_use_rate; + //private float gpu_use_rate; + //private float mem_use_rate; + + public float getCpuUseRate() + { + return this.cpu_user+this.cpu_system; + } + + public String getServerStatus() + { + String enumId = "SAFETY"; + //if( this.cpu_user+this.cpu_system >= 80 )enumId = "CAUTION"; + return enumId; + } + + public String getServerStatusName() + { + //String enumId = "SAFETY"; + //if( this.cpu_user+this.cpu_system >= 80 )enumId = "CAUTION"; + return ServerStatus.SAFETY.getText(); + } + + public String getCpuStatus() + { + String enumId = "SAFETY"; + if( this.cpu_user+this.cpu_system >= 80 )enumId = "CAUTION"; + return enumId; + } + + public String getGpuStatus() + { + String enumId = "SAFETY"; + if( this.gpuUtil >= 80 )enumId = "CAUTION"; + return enumId; + } + + public String getMemStatus() + { + String enumId = "SAFETY"; + if( this.memused >= 80 )enumId = "CAUTION"; + return enumId; + } + + public String getCpuStatusName() + { + if( this.cpu_user+this.cpu_system >= 80 )return ServerStatus.CAUTION.getText(); + return ServerStatus.SAFETY.getText(); + } + + public String getGpuStatusName() + { + if( this.gpuUtil >= 80 )return ServerStatus.CAUTION.getText(); + return ServerStatus.SAFETY.getText(); + } + + public String getMemStatusName() + { + if( this.memused >= 80 )return ServerStatus.CAUTION.getText(); + return ServerStatus.SAFETY.getText(); + } + + + } + + + @Getter + @AllArgsConstructor + public enum ServerStatus implements EnumType { + SAFETY("원활"), + CAUTION("주의"), + FAILUR("장애"), + ; + + private final String desc; + + @Override + public String getId() { + return name(); + } + + @Override + public String getText() { + return desc; + } + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java index 11f11669..705936bc 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java @@ -1,6 +1,8 @@ package com.kamco.cd.kamcoback.inference.service; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.kamco.cd.kamcoback.common.exception.CustomApiException; import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient; import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient.ExternalCallResult; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto; @@ -9,6 +11,7 @@ import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Detail; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.MapSheet; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.DetectOption; +import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheetNumDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheetScope; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.ResultList; @@ -23,6 +26,7 @@ import com.kamco.cd.kamcoback.postgres.core.ModelMngCoreService; import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -33,6 +37,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -93,7 +98,7 @@ public class InferenceResultService { // 추론 테이블 저장 UUID uuid = inferenceResultCoreService.saveInferenceInfo(req); - this.startInference(req); + this.startInference(req, uuid); return uuid; } @@ -165,7 +170,7 @@ public class InferenceResultService { * * @param req */ - private void startInference(InferenceResultDto.RegReq req) { + private void startInference(InferenceResultDto.RegReq req, UUID uuid) { List mapSheetNum = req.getMapSheetNum(); List mapSheetNumList = new ArrayList<>(); @@ -193,9 +198,8 @@ public class InferenceResultService { m2.setPred_requests_areas(predRequestsAreas); m3.setPred_requests_areas(predRequestsAreas); - ensureAccepted(m1); - // ensureAccepted(m2); - // ensureAccepted(m3); + Long batchId = this.ensureAccepted(m1); + inferenceResultCoreService.update(uuid, batchId, "IN_PROGRESS"); } /** @@ -203,7 +207,7 @@ public class InferenceResultService { * * @param dto */ - private void ensureAccepted(InferenceSendDto dto) { + private Long ensureAccepted(InferenceSendDto dto) { log.info("dto null? {}", dto == null); ObjectMapper om = new ObjectMapper(); try { @@ -227,6 +231,28 @@ public class InferenceResultService { int status = result.statusCode(); String body = result.body(); + + if (status < 200 || status >= 300) { + throw new CustomApiException("BAD_GATEWAY", HttpStatus.BAD_GATEWAY); + } + + Long batchId = 0L; + + try { + List> list = + om.readValue(body, new TypeReference>>() {}); + + Integer batchIdInt = (Integer) list.get(0).get("batch_id"); + batchId = batchIdInt.longValue(); + if (list.isEmpty()) { + throw new IllegalStateException("Inference response is empty"); + } + + } catch (Exception e) { + log.error(e.getMessage()); + } + + return batchId; } /** @@ -361,4 +387,8 @@ public class InferenceResultService { public List listGetScenes5k(Long id) { return inferenceResultCoreService.listGetScenes5k(id); } + + public List getInferenceServerStatusList() { + return inferenceResultCoreService.getInferenceServerStatusList(); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java index 3c7b3933..1d7710a1 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java @@ -6,6 +6,7 @@ import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Dashboard; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.MapSheet; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; +import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheetNumDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.ResultList; import com.kamco.cd.kamcoback.postgres.entity.MapInkx5kEntity; @@ -216,4 +217,17 @@ public class InferenceResultCoreService { .map(MapInkx5kEntity::toEntity) .toList(); } + + public void update(UUID uuid, Long batchId, String status) { + MapSheetLearnEntity entity = + mapSheetLearnRepository + .getInferenceResultByUuid(uuid) + .orElseThrow(() -> new EntityNotFoundException(uuid.toString())); + + entity.setBatchId(batchId); + entity.setStatus(status); + } + + public List getInferenceServerStatusList(){return mapSheetLearnRepository.getInferenceServerStatusList(); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/GpuMetricEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/GpuMetricEntity.java new file mode 100644 index 00000000..55fee73d --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/GpuMetricEntity.java @@ -0,0 +1,48 @@ +package com.kamco.cd.kamcoback.postgres.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import java.time.OffsetDateTime; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; + +@Getter +@Setter +@Entity +@Table(name = "gpu_metrics") +public class GpuMetricEntity { + + @Id + @ColumnDefault("gen_random_uuid()") + @Column(name = "uuid", nullable = false) + private UUID id; + + @NotNull + @ColumnDefault("nextval('gpu_metrics_id_seq')") + @Column(name = "id", nullable = false) + private Integer id1; + + @NotNull + @ColumnDefault("now()") + @Column(name = "\"timestamp\"", nullable = false) + private OffsetDateTime timestamp; + + @NotNull + @Column(name = "server_name", nullable = false, length = Integer.MAX_VALUE) + private String serverName; + + @Column(name = "gpu_util") + private Float gpuUtil; + + @Column(name = "gpu_mem_used") + private Float gpuMemUsed; + + @Column(name = "gpu_mem_total") + private Float gpuMemTotal; + +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java index de34ca1a..8e70a514 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java @@ -40,7 +40,7 @@ public class MapSheetLearnEntity { @Column(name = "title", nullable = false, length = 200) private String title; - @Size(max = 10) + @Size(max = 20) @Column(name = "status", length = 10) private String status; @@ -103,6 +103,9 @@ public class MapSheetLearnEntity { @Column(name = "updated_uid") private Long updatedUid; + @Column(name = "batch_id") + private Long batchId; + public InferenceResultDto.ResultList toDto() { return new InferenceResultDto.ResultList( this.uuid, diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/SystemMetricEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/SystemMetricEntity.java new file mode 100644 index 00000000..eb072a3f --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/SystemMetricEntity.java @@ -0,0 +1,59 @@ +package com.kamco.cd.kamcoback.postgres.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import java.time.OffsetDateTime; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; + +@Getter +@Setter +@Entity +@Table(name = "system_metrics") +public class SystemMetricEntity { + + @Id + @ColumnDefault("gen_random_uuid()") + @Column(name = "uuid", nullable = false) + private UUID id; + + @NotNull + @ColumnDefault("nextval('system_metrics_id_seq')") + @Column(name = "id", nullable = false) + private Integer id1; + + @NotNull + @Column(name = "\"timestamp\"", nullable = false) + private OffsetDateTime timestamp; + + @NotNull + @Column(name = "server_name", nullable = false, length = Integer.MAX_VALUE) + private String serverName; + + @Column(name = "cpu_user") + private Float cpuUser; + + @Column(name = "cpu_system") + private Float cpuSystem; + + @Column(name = "cpu_iowait") + private Float cpuIowait; + + @Column(name = "cpu_idle") + private Float cpuIdle; + + @Column(name = "kbmemfree") + private Long kbmemfree; + + @Column(name = "kbmemused") + private Long kbmemused; + + @Column(name = "memused") + private Float memused; + +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryCustom.java index f541f0c9..4d896aa3 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryCustom.java @@ -1,10 +1,18 @@ package com.kamco.cd.kamcoback.postgres.repository.Inference; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; +import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto; import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnEntity; +import java.util.Optional; +import java.util.UUID; +import java.util.List; import org.springframework.data.domain.Page; public interface MapSheetLearnRepositoryCustom { Page getInferenceMgnResultList(InferenceResultDto.SearchListReq req); + + Optional getInferenceResultByUuid(UUID uuid); + + List getInferenceServerStatusList(); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java index ab9e38fe..79c7e827 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java @@ -1,15 +1,21 @@ package com.kamco.cd.kamcoback.postgres.repository.Inference; +import static com.kamco.cd.kamcoback.postgres.entity.QGpuMetricEntity.gpuMetricEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnEntity.mapSheetLearnEntity; +import static com.kamco.cd.kamcoback.postgres.entity.QSystemMetricEntity.systemMetricEntity; import com.kamco.cd.kamcoback.common.utils.DateRange; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; +import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto; import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnEntity; import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.CaseBuilder; import com.querydsl.core.types.dsl.NumberExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; +import java.util.Optional; +import java.util.UUID; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Page; @@ -73,4 +79,50 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto return new PageImpl<>(content, pageable, total == null ? 0L : total); } + + @Override + public Optional getInferenceResultByUuid(UUID uuid) { + return Optional.ofNullable( + queryFactory + .selectFrom(mapSheetLearnEntity) + .where(mapSheetLearnEntity.uuid.eq(uuid)) + .fetchOne()); + } + + @Override + public List getInferenceServerStatusList() { + + BooleanBuilder builder = new BooleanBuilder(); + + List latestIds = queryFactory + .select(systemMetricEntity.id1.max()) + .from(systemMetricEntity) + .groupBy(systemMetricEntity.serverName) + .fetch(); + + List latestGpuIds = queryFactory + .select(gpuMetricEntity.id1.max()) + .from(gpuMetricEntity) + .groupBy(gpuMetricEntity.serverName) + .fetch(); + + List foundContent = queryFactory + .select(Projections.constructor( + InferenceServerStatusDto.class, + systemMetricEntity.serverName, + systemMetricEntity.cpuUser, + systemMetricEntity.cpuSystem, + systemMetricEntity.memused, + systemMetricEntity.kbmemused, + gpuMetricEntity.gpuUtil + )) + .from(systemMetricEntity) + .leftJoin(gpuMetricEntity).on(gpuMetricEntity.serverName.eq(systemMetricEntity.serverName)) + .where(systemMetricEntity.id1.in(latestIds)) // In 절 사용 + .orderBy(systemMetricEntity.serverName.asc()) + .limit(4) + .fetch(); + + return foundContent; + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java new file mode 100644 index 00000000..174eeb80 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java @@ -0,0 +1,30 @@ +package com.kamco.cd.kamcoback.scheduler.service; + +import com.kamco.cd.kamcoback.postgres.core.InferenceResultCoreService; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +@Log4j2 +@Service +@RequiredArgsConstructor +public class MapSheetInferenceJobService { + + private final InferenceResultCoreService inferenceResultCoreService; + + @Scheduled(fixedDelay = 60_000) + public void runBatch() { + log.info("1분 배치 시작"); + + try { + // TODO: 배치 로직 작성 + Thread.sleep(3000); // 예시: 처리 시간 3초 + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("배치 중 인터럽트 발생", e); + } + + log.info("1분 배치 종료"); + } +}