JobManager 에 완료 시각을 기록하고, 일정 시간(예: 10분)이 지난 DONE·FAILED·CANCELLED 작업을 맵에서 제거하는 정리 스레드를 추가하세요. 힌트: ScheduledExecutorService 로 주기적으로 순회합니다.
private final ScheduledExecutorService cleaner =
Executors.newSingleThreadScheduledExecutor();
// 생성자나 초기화 블록에서
cleaner.scheduleAtFixedRate(() -> {
long now = System.currentTimeMillis();
jobs.values().removeIf(j ->
!isActive(j.status) && now - j.finishedAt > 10 * 60 * 1000);
}, 1, 1, TimeUnit.MINUTES);Job 에 volatile long finishedAt 필드를 추가하고, run() 에서 DONE·FAILED·CANCELLED 로 상태를 바꿀 때마다 finishedAt = System.currentTimeMillis() 를 함께 기록해야 합니다.
FAILED 상태인 작업을 같은 owner·total 로 다시 제출하는 엔드포인트를 만드세요. FAILED 가 아니면 409 를 반환합니다.
static void handleRetry(HttpExchange ex, String id) throws IOException {
JobManager.Job old = jobManager.get(id);
if (old == null) { sendText(ex, 404, "no such job"); return; }
if (!"FAILED".equals(old.status)) {
sendText(ex, 409, "FAILED 상태만 재시도 가능: " + old.status);
return;
}
JobManager.Job job = jobManager.submit(old.owner, old.total);
sendJson(ex, 202, "{\"id\":\"" + job.id + "\",\"statusUrl\":\"/jobs/" + job.id + "\"}");
}handleJobs 의 라우팅 분기에 p.length == 4 && "POST".equals(method) && "retry".equals(p[3]) 조건을 추가해 연결합니다.
GET /jobs (전체 목록 없이) 대신, 서버 전체 대기열 크기를 보여주는 GET /queue-status 를 추가하세요. ThreadPoolExecutor 의 메서드를 활용합니다.
static void handleQueueStatus(HttpExchange ex) throws IOException {
ThreadPoolExecutor pool = jobManager.poolForMonitoring();
String body = "{\"active\":" + pool.getActiveCount()
+ ",\"queued\":" + pool.getQueue().size()
+ ",\"completed\":" + pool.getCompletedTaskCount() + "}";
sendJson(ex, 200, body);
}JobManager 에 pool 필드를 반환하는 poolForMonitoring() 같은 접근자를 하나 추가해야 호출할 수 있습니다. 운영에서는 이 값을 모니터링 대시보드나 액추에이터 지표로 노출합니다.