접속오류 수정
This commit is contained in:
+4
-4
@@ -12,20 +12,20 @@ import org.springframework.stereotype.Component;
|
||||
public class StrategyEvaluationAiVerifyJobRunner {
|
||||
|
||||
private final StrategyEvaluationLlmService llmService;
|
||||
private final StrategyEvaluationAiVerifyJobService jobService;
|
||||
private final StrategyEvaluationAiVerifyJobStore jobStore;
|
||||
|
||||
@Async("aiVerifyExecutor")
|
||||
public void execute(String jobId, JsonNode context, Long userId, String deviceId) {
|
||||
jobService.markRunning(jobId);
|
||||
jobStore.markRunning(jobId);
|
||||
try {
|
||||
var result = llmService.verify(context, userId, deviceId);
|
||||
jobService.markCompleted(jobId, result);
|
||||
jobStore.markCompleted(jobId, result);
|
||||
} catch (Exception e) {
|
||||
log.warn("[AiVerifyJob] fail jobId={}: {}", jobId, e.getMessage());
|
||||
String msg = e.getMessage() != null && !e.getMessage().isBlank()
|
||||
? e.getMessage()
|
||||
: "AI 검증 중 오류가 발생했습니다.";
|
||||
jobService.markFailed(jobId, msg);
|
||||
jobStore.markFailed(jobId, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-85
@@ -3,110 +3,29 @@ package com.goldenchart.service;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.goldenchart.dto.StrategyEvaluationAiVerifyJobStartResponse;
|
||||
import com.goldenchart.dto.StrategyEvaluationAiVerifyJobStatusResponse;
|
||||
import com.goldenchart.dto.StrategyEvaluationAiVerifyResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class StrategyEvaluationAiVerifyJobService {
|
||||
|
||||
private static final long JOB_TTL_MS = 60L * 60 * 1000;
|
||||
|
||||
private final StrategyEvaluationAiVerifyJobRunner jobRunner;
|
||||
|
||||
private final ConcurrentHashMap<String, JobRecord> jobs = new ConcurrentHashMap<>();
|
||||
private final StrategyEvaluationAiVerifyJobStore jobStore;
|
||||
|
||||
public StrategyEvaluationAiVerifyJobStartResponse startJob(JsonNode context, Long userId, String deviceId) {
|
||||
purgeExpired();
|
||||
String jobId = UUID.randomUUID().toString();
|
||||
JobRecord record = new JobRecord(jobId, userId, System.currentTimeMillis());
|
||||
jobs.put(jobId, record);
|
||||
jobStore.register(jobId, userId);
|
||||
jobRunner.execute(jobId, context, userId, deviceId);
|
||||
return StrategyEvaluationAiVerifyJobStartResponse.builder()
|
||||
.jobId(jobId)
|
||||
.status(record.status)
|
||||
.status(jobStore.initialStatus(jobId))
|
||||
.build();
|
||||
}
|
||||
|
||||
public StrategyEvaluationAiVerifyJobStatusResponse getJob(String jobId, Long userId) {
|
||||
purgeExpired();
|
||||
JobRecord record = jobs.get(jobId);
|
||||
if (record == null || !record.userId.equals(userId)) {
|
||||
return null;
|
||||
}
|
||||
return toResponse(record);
|
||||
}
|
||||
|
||||
void markRunning(String jobId) {
|
||||
JobRecord record = jobs.get(jobId);
|
||||
if (record != null) {
|
||||
record.status = "RUNNING";
|
||||
}
|
||||
}
|
||||
|
||||
void markCompleted(String jobId, StrategyEvaluationAiVerifyResponse result) {
|
||||
JobRecord record = jobs.get(jobId);
|
||||
if (record != null) {
|
||||
record.status = "COMPLETED";
|
||||
record.result = result;
|
||||
record.error = null;
|
||||
record.completedAtMs = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
void markFailed(String jobId, String error) {
|
||||
JobRecord record = jobs.get(jobId);
|
||||
if (record != null) {
|
||||
record.status = "FAILED";
|
||||
record.error = error;
|
||||
record.completedAtMs = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
private static StrategyEvaluationAiVerifyJobStatusResponse toResponse(JobRecord record) {
|
||||
return StrategyEvaluationAiVerifyJobStatusResponse.builder()
|
||||
.jobId(record.jobId)
|
||||
.status(record.status)
|
||||
.error(record.error)
|
||||
.result(record.result)
|
||||
.createdAtMs(record.createdAtMs)
|
||||
.completedAtMs(record.completedAtMs)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void purgeExpired() {
|
||||
long cutoff = System.currentTimeMillis() - JOB_TTL_MS;
|
||||
Iterator<Map.Entry<String, JobRecord>> it = jobs.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, JobRecord> e = it.next();
|
||||
long ts = e.getValue().completedAtMs != null
|
||||
? e.getValue().completedAtMs
|
||||
: e.getValue().createdAtMs;
|
||||
if (ts < cutoff) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class JobRecord {
|
||||
private final String jobId;
|
||||
private final Long userId;
|
||||
private final long createdAtMs;
|
||||
private String status = "QUEUED";
|
||||
private String error;
|
||||
private StrategyEvaluationAiVerifyResponse result;
|
||||
private Long completedAtMs;
|
||||
|
||||
private JobRecord(String jobId, Long userId, long createdAtMs) {
|
||||
this.jobId = jobId;
|
||||
this.userId = userId;
|
||||
this.createdAtMs = createdAtMs;
|
||||
}
|
||||
return jobStore.getJob(jobId, userId);
|
||||
}
|
||||
}
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package com.goldenchart.service;
|
||||
|
||||
import com.goldenchart.dto.StrategyEvaluationAiVerifyJobStatusResponse;
|
||||
import com.goldenchart.dto.StrategyEvaluationAiVerifyResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/** AI 검증 job 상태 저장 — Service·Runner 간 순환 참조 방지 */
|
||||
@Component
|
||||
public class StrategyEvaluationAiVerifyJobStore {
|
||||
|
||||
private static final long JOB_TTL_MS = 60L * 60 * 1000;
|
||||
|
||||
private final ConcurrentHashMap<String, JobRecord> jobs = new ConcurrentHashMap<>();
|
||||
|
||||
public void register(String jobId, Long userId) {
|
||||
purgeExpired();
|
||||
jobs.put(jobId, new JobRecord(jobId, userId, System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
public StrategyEvaluationAiVerifyJobStatusResponse getJob(String jobId, Long userId) {
|
||||
purgeExpired();
|
||||
JobRecord record = jobs.get(jobId);
|
||||
if (record == null || !record.userId.equals(userId)) {
|
||||
return null;
|
||||
}
|
||||
return toResponse(record);
|
||||
}
|
||||
|
||||
public String initialStatus(String jobId) {
|
||||
JobRecord record = jobs.get(jobId);
|
||||
return record != null ? record.status : "QUEUED";
|
||||
}
|
||||
|
||||
public void markRunning(String jobId) {
|
||||
JobRecord record = jobs.get(jobId);
|
||||
if (record != null) {
|
||||
record.status = "RUNNING";
|
||||
}
|
||||
}
|
||||
|
||||
public void markCompleted(String jobId, StrategyEvaluationAiVerifyResponse result) {
|
||||
JobRecord record = jobs.get(jobId);
|
||||
if (record != null) {
|
||||
record.status = "COMPLETED";
|
||||
record.result = result;
|
||||
record.error = null;
|
||||
record.completedAtMs = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
public void markFailed(String jobId, String error) {
|
||||
JobRecord record = jobs.get(jobId);
|
||||
if (record != null) {
|
||||
record.status = "FAILED";
|
||||
record.error = error;
|
||||
record.completedAtMs = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
private static StrategyEvaluationAiVerifyJobStatusResponse toResponse(JobRecord record) {
|
||||
return StrategyEvaluationAiVerifyJobStatusResponse.builder()
|
||||
.jobId(record.jobId)
|
||||
.status(record.status)
|
||||
.error(record.error)
|
||||
.result(record.result)
|
||||
.createdAtMs(record.createdAtMs)
|
||||
.completedAtMs(record.completedAtMs)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void purgeExpired() {
|
||||
long cutoff = System.currentTimeMillis() - JOB_TTL_MS;
|
||||
Iterator<Map.Entry<String, JobRecord>> it = jobs.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, JobRecord> e = it.next();
|
||||
long ts = e.getValue().completedAtMs != null
|
||||
? e.getValue().completedAtMs
|
||||
: e.getValue().createdAtMs;
|
||||
if (ts < cutoff) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class JobRecord {
|
||||
private final String jobId;
|
||||
private final Long userId;
|
||||
private final long createdAtMs;
|
||||
private String status = "QUEUED";
|
||||
private String error;
|
||||
private StrategyEvaluationAiVerifyResponse result;
|
||||
private Long completedAtMs;
|
||||
|
||||
private JobRecord(String jobId, Long userId, long createdAtMs) {
|
||||
this.jobId = jobId;
|
||||
this.userId = userId;
|
||||
this.createdAtMs = createdAtMs;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user