생성이 끝나지 않으면 이미 받은 요청도 사용량에서 빠진다
슬라이드 이미지와 영상 사용량은 생성이 완료된 뒤 카운터에 더해진다. 한도가 10장이고 완료 사용량이 8장일 때, 이미 2장을 생성 중이라면 다음 요청이 볼 잔여량은 달라야 한다. 완료 카운터만 읽으면 이 2장이 아직 없는 것처럼 판단한다.
AI Commons에서는 생성 허용 판단에 요청자 본인의 대기·처리 중 작업 예상량을 더했다. 생성 가드와 사전 확인에 같은 계산을 사용하고, 실제 제출 시점에도 다시 검사한다. 완료분 used와 진행분 pending은 따로 유지해, 확정 사용량과 추정을 화면과 응답에서 구분한다.
| 검사 | 완료분 | 본인 진행분 | 요청량·한도 | 기대 판정 |
|---|---|---|---|---|
| 총량 진입 가드 | 8 | 2 | 한도 10 | 총량 도달로 차단 |
| 요청량을 아는 사전 확인 | 5 | 3 | 요청 3, 한도 10 | 잔여량 부족으로 차단 |
| 개인 진입 가드 | 4 | 1 | 개인 한도 5 | 개인 한도 도달로 차단 |
진입 가드는 완료+진행 사용량이 한도에 도달했는지 보고, 작업량을 아는 사전 확인은 완료+진행+요청이 한도를 넘는지 본다. 같은 카운터를 읽어도 요청량을 포함할 수 있는 시점의 판단은 더 구체적이다.
작업 수와 사용량은 같은 단위가 아니다
대상 상태는 QUEUED와 PROCESSING이다. 이미지 일괄 생성은 슬라이드의 totalPages를 최소 1장으로 보정하고, 단일 이미지 재생성은 1장으로 센다. 소유자는 잡 자체의 필드가 아니라 slide.userId 또는 video.userId 관계로 좁힌다.
영상은 TTS_COMPOSE 잡의 슬라이드 스크립트와 언어로 시간을 추정한다. 한국어는 분당 400자, 영어는 분당 150단어를 기준으로 초를 계산한 뒤, 페이지별 초를 합쳐 분 단위로 올림한다. 슬라이드가 연결된 영상의 최소 추정은 1분이며, 슬라이드가 없는 영상은 이 방식으로 추정할 수 없어 제외한다. 완성된 영상의 실제 길이와 같은 값이라고 볼 수는 없다.
총량과 개인 한도는 같은 요청에서 진행량을 한 번만 조회해 재사용한다. 유한 한도를 검사할 때 조회하고, 양쪽 모두 무제한이면 조회를 생략한다. 아래는 이 지연 조회 부분이다.
let pendingCache: number | undefined;
const getPending = async (): Promise<number> => {
if (!includeOwnInFlight) return 0;
if (pendingCache === undefined) {
pendingCache = await estimateInFlightUsage(prisma, user, kind);
}
return pendingCache;
}; 진행량을 더하지 않는 표시 경로와 무제한 단축 경로는 기존 동작을 유지한다. 강화한 판단에는 잡·스크립트 조회 비용과 시간 추정 오차가 추가된다. 공유한 계산 함수는 사전 확인과 진행량의 산식 차이를 줄여 주지만, 그 추정을 확정값으로 바꾸지는 않는다.
관측한 진행량을 더해도 다음 요청의 몫을 예약하지는 않는다
이 조회가 더하는 값은 본인의 이미 기록된 진행 작업이다. 기관 총량 판단에도 다른 사용자의 모든 진행량을 합쳐 예약하지 않는다. 동시에 들어온 두 요청이 아직 잡을 만들지 않았다면, 양쪽 조회에 상대 요청이 보이지 않을 수 있다. 조회, 승인, 잡 생성은 하나의 원자 연산이 아니다.
더 강한 제한에는 승인과 함께 사용량을 예약하고, 실패·취소 때 해제하며, 완료 뒤 실제 사용량으로 정산하는 규칙이 필요하다. 이번 변경은 완료 시점의 가산 정책과 일시 초과를 허용하는 정책을 유지하면서, 이미 관측할 수 있는 본인 작업의 누락을 줄였다.
판정 테스트는 DB와 추정 함수를 mock으로 두고 위 합산·차단 분기를 검사한다. 별도 추정 테스트는 일괄/단일 이미지, 0페이지 보정, 소유자·상태 필터, 영상 스크립트와 슬라이드 미연결을 다룬다. 이 검사는 실제 두 요청의 동시 승인 경합이나 생성 영상 길이의 추정 오차를 측정하지 않는다.