[Feat] 인덱싱 실패 종료 및 지연 재시도 - #89
Conversation
📝 WalkthroughWalkthrough인덱싱 실패 종료 API를 추가했습니다. 서버가 실패 유형과 재시도 횟수를 기준으로 지연 재시도 또는 최종 실패를 처리합니다. Job Claim에 Changes인덱싱 실패 및 재시도
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Worker
participant IndexingJobAdminController
participant DocumentIndexingFailureService
participant EmbeddingJob
participant DocumentVersion
participant Document
Worker->>IndexingJobAdminController: 실패 API 요청
IndexingJobAdminController->>DocumentIndexingFailureService: 실패 처리 호출
DocumentIndexingFailureService->>EmbeddingJob: 소유권 검증 및 Job 잠금
DocumentIndexingFailureService->>DocumentVersion: Version 상태 확인
DocumentIndexingFailureService->>Document: 검색 상태 확인 및 갱신
DocumentIndexingFailureService->>EmbeddingJob: 재시도 예약 또는 최종 실패
DocumentIndexingFailureService-->>IndexingJobAdminController: 고정 실패 응답
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (5)
src/main/java/com/opensource/docgrid/domain/embedding/repository/EmbeddingJobRepository.java (1)
42-53: 🚀 Performance & Scalability | 🔵 TrivialQueue 조회 인덱스 선택을 실행 계획으로 확인하십시오.
이 쿼리는
status로 필터하고priority DESC, created_at ASC, id ASC로 정렬합니다. 기존idx_embedding_jobs_status_priority_created_at가 정렬을 담당합니다. 새idx_embedding_jobs_status_next_retry_at는 정렬 컬럼을 포함하지 않으므로 이 쿼리에서 선택되지 않을 가능성이 큽니다. PENDING Job이 많고 대부분 Retry 예약 상태이면, 정렬 인덱스를 스캔하며next_retry_at조건으로 대량 행을 버리게 됩니다.운영 규모가 커지면
EXPLAIN ANALYZE로 실제 계획을 확인하고, 필요 시(status, priority, created_at, id)기반 부분 인덱스 또는next_retry_at을 포함한 복합 인덱스를 검토하십시오. 현재 변경 자체는 정확합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/opensource/docgrid/domain/embedding/repository/EmbeddingJobRepository.java` around lines 42 - 53, Validate the query plan for findNextPendingForUpdate with EXPLAIN ANALYZE at production-like scale, focusing on index selection and rows filtered by next_retry_at. If the existing indexes cause excessive scanning, add or adjust an index using status, priority, created_at, and id, optionally incorporating next_retry_at as appropriate, while preserving the query’s filtering and ordering behavior.src/test/java/com/opensource/docgrid/domain/embedding/entity/EmbeddingJobTest.java (1)
121-148: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
scheduleRetry의 나머지 두 방어 분기도 테스트하십시오.현재 테스트는 Retry 소진 분기만 검증합니다.
scheduleRetry에는 두 개의 방어 로직이 더 있습니다.
- PROCESSING이 아닌 Job은
IllegalStateException("PROCESSING 상태의 Job만 Retry를 예약할 수 있습니다.")를 던진다.nextRetryAt이 null이면IllegalArgumentException("다음 Retry 시각은 필수입니다.")를 던진다.두 분기는 현재 커버되지 않습니다.
♻️ 추가 테스트 제안
`@Test` `@DisplayName`("PROCESSING이 아닌 Job은 Retry를 예약할 수 없다") void scheduleRetry_throws_when_jobIsNotProcessing() { EmbeddingJob pendingJob = createPendingJob(); assertThatThrownBy(() -> pendingJob.scheduleRetry( "STORAGE_UNAVAILABLE", "Storage timeout", CLAIMED_AT.plusSeconds(10) )).isInstanceOf(IllegalStateException.class) .hasMessage("PROCESSING 상태의 Job만 Retry를 예약할 수 있습니다."); assertThat(pendingJob.getStatus()).isEqualTo(EmbeddingJobStatus.PENDING); } `@Test` `@DisplayName`("다음 Retry 시각이 없으면 예약할 수 없다") void scheduleRetry_throws_when_nextRetryAtIsNull() { EmbeddingJob embeddingJob = createPendingJob(); embeddingJob.claim(createActiveWorker(), CLAIM_TOKEN, CLAIMED_AT, EXPIRES_AT); assertThatThrownBy(() -> embeddingJob.scheduleRetry("STORAGE_UNAVAILABLE", "Storage timeout", null)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("다음 Retry 시각은 필수입니다."); assertThat(embeddingJob.getStatus()).isEqualTo(EmbeddingJobStatus.PROCESSING); assertThat(embeddingJob.getRetryCount()).isZero(); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/com/opensource/docgrid/domain/embedding/entity/EmbeddingJobTest.java` around lines 121 - 148, Extend EmbeddingJobTest with coverage for the two untested scheduleRetry guards: add a test using a non-PROCESSING job that asserts the expected IllegalStateException message and unchanged PENDING status, and a test using a claimed PROCESSING job with null nextRetryAt that asserts the expected IllegalArgumentException message, unchanged PROCESSING status, and zero retry count.src/test/java/com/opensource/docgrid/domain/worker/config/IndexingWorkerPropertiesTest.java (1)
49-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win경계값과 음수 케이스를 추가하십시오.
isRetryDelayValid는retryMaxDelay.compareTo(retryInitialDelay) >= 0을 사용합니다. 두 값이 같을 때 유효하다는 경계 동작이 현재 고정되지 않았습니다. 누군가>=를>로 바꿔도 테스트가 통과합니다. 또한 인접한leaseDuration_isInvalid_when_notPositive는 음수까지 검증하지만, 이 테스트는Duration.ZERO만 검증합니다.♻️ 단언 추가 제안
void retryDelay_isInvalid_when_nonPositiveOrReversed() { IndexingWorkerProperties properties = new IndexingWorkerProperties(); properties.setRetryInitialDelay(Duration.ZERO); assertThat(properties.isRetryDelayValid()).isFalse(); + properties.setRetryInitialDelay(Duration.ofSeconds(-1)); + assertThat(properties.isRetryDelayValid()).isFalse(); + properties.setRetryInitialDelay(Duration.ofSeconds(10)); properties.setRetryMaxDelay(Duration.ofSeconds(9)); assertThat(properties.isRetryDelayValid()).isFalse(); + + properties.setRetryMaxDelay(Duration.ofSeconds(10)); + assertThat(properties.isRetryDelayValid()).isTrue(); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/com/opensource/docgrid/domain/worker/config/IndexingWorkerPropertiesTest.java` around lines 49 - 60, 보강된 retry delay 테스트에서 isRetryDelayValid의 경계값과 음수 입력을 고정하십시오. retryInitialDelay와 retryMaxDelay가 동일한 양수 Duration일 때 유효함을 단언하고, retryInitialDelay가 음수일 때 유효하지 않음을 검증하십시오. 기존의 0 이하 및 역전된 최대 지연 검증은 유지하십시오.src/main/resources/db/migration/V35__add_embedding_job_next_retry_at.sql (1)
5-6: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value대용량 테이블이면 인덱스 생성 방식을 검토하십시오.
일반
CREATE INDEX는 생성 중 해당 테이블의 쓰기를 차단합니다.embedding_jobs행이 많으면 배포 중 인덱싱 Queue 쓰기가 멈출 수 있습니다.CREATE INDEX CONCURRENTLY는 트랜잭션 안에서 실행할 수 없으므로, 사용하려면 해당 마이그레이션의 트랜잭션 실행을 비활성화해야 합니다. 현재 테이블 규모가 작으면 지금 형태를 유지해도 됩니다.참고:
ADD COLUMN next_retry_at TIMESTAMP는 기본값이 없어 테이블 rewrite를 유발하지 않습니다. 이 부분은 안전합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/resources/db/migration/V35__add_embedding_job_next_retry_at.sql` around lines 5 - 6, Review the migration’s expected table size and deployment requirements for the index created by idx_embedding_jobs_status_next_retry_at. If embedding_jobs may be large, switch this index creation to the concurrent form and disable transactional execution for the migration; otherwise retain the current CREATE INDEX behavior. Leave the next_retry_at column addition unchanged.Source: Linters/SAST tools
src/test/java/com/opensource/docgrid/domain/worker/entity/EmbeddingJobAttemptTest.java (1)
103-112: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win최초
durationMs도 유지되는지 검증하세요.재실패 요청은 최초 실패 결과 전체를 보존해야 합니다. Lines 110-112는 종료 시각과 오류 정보만 확인합니다.
assertThat(attempt.getDurationMs()).isEqualTo(2_000L);를 추가하세요.As per path instructions, 테스트 커버리지, 스프링 테스트 어노테이션, mock 사용법, 네이밍 규칙을 확인한다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/com/opensource/docgrid/domain/worker/entity/EmbeddingJobAttemptTest.java` around lines 103 - 112, Update the existing assertions in EmbeddingJobAttemptTest around markFailed to also verify that the original failure duration is preserved: assert attempt.getDurationMs() remains 2_000L after the repeated failure request, alongside the existing endedAt and error assertions.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/test-results/Gimini-3-`#88-document-indexing-failure-retry.md:
- Around line 14-70: 문서의 자동 테스트 결과에 새 관리자 실패 API의 Swagger 수동 검증 결과를 추가하세요. 최초
실패, 멱등 재시도, 요청 검증 실패, 소유권 충돌 및 상태 충돌 각각에 대해 실제 요청과 응답 상태를 기록하고, 기존 자동 테스트 결과와 같은
문서에서 함께 정리하세요. 파일명은 {github아이디}-#{이슈번호}-{설명}.md 규칙을 유지하세요.
In
`@src/main/java/com/opensource/docgrid/domain/embedding/converter/EmbeddingJobAttemptConverter.java`:
- Around line 31-40: Validate failure codes before persistence in the
Application save path, especially where
FailDocumentIndexingRequest.failureType().name() is stored, and reject or
normalize values not defined by IndexingFailureType. Update
EmbeddingJobAttemptConverter.toFailureResponse to handle legacy or manually
stored unknown codes without allowing IndexingFailureType.valueOf to throw,
mapping them to the established compatible failure type or excluding them
according to the domain contract.
In `@src/main/resources/application.yml`:
- Around line 27-28: 운영 기본 Retry Backoff 정책을 테스트와 일치시키세요.
src/main/resources/application.yml 27-28행의 retry-max-delay를 고정 10s-20s-40s 정책에
맞게 40s로 조정하고,
src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.java
88-90행의 검증도 동일한 상한을 사용하도록 정리하세요. 5분 상한을 유지해야 한다면 해당 정책에 맞춰 두 위치의 테스트 기대값과 지연 검증을
확장하세요.
In
`@src/test/java/com/opensource/docgrid/domain/document/entity/DocumentVersionTest.java`:
- Line 16: Update the class-level comment in DocumentVersionTest to include the
UPLOADED-to-FAILED state transition alongside the existing pipeline states,
keeping the documented test scope consistent with the assertions around the
UPLOADED failure transition.
In
`@src/test/java/com/opensource/docgrid/domain/embedding/integration/DocumentIndexingFailureIntegrationTest.java`:
- Around line 43-54: Update the class Javadoc and `@DisplayName` in
DocumentIndexingFailureIntegrationTest to replace “OpenSQL” with “PostgreSQL,”
preserving the existing description and test behavior.
---
Nitpick comments:
In
`@src/main/java/com/opensource/docgrid/domain/embedding/repository/EmbeddingJobRepository.java`:
- Around line 42-53: Validate the query plan for findNextPendingForUpdate with
EXPLAIN ANALYZE at production-like scale, focusing on index selection and rows
filtered by next_retry_at. If the existing indexes cause excessive scanning, add
or adjust an index using status, priority, created_at, and id, optionally
incorporating next_retry_at as appropriate, while preserving the query’s
filtering and ordering behavior.
In `@src/main/resources/db/migration/V35__add_embedding_job_next_retry_at.sql`:
- Around line 5-6: Review the migration’s expected table size and deployment
requirements for the index created by idx_embedding_jobs_status_next_retry_at.
If embedding_jobs may be large, switch this index creation to the concurrent
form and disable transactional execution for the migration; otherwise retain the
current CREATE INDEX behavior. Leave the next_retry_at column addition
unchanged.
In
`@src/test/java/com/opensource/docgrid/domain/embedding/entity/EmbeddingJobTest.java`:
- Around line 121-148: Extend EmbeddingJobTest with coverage for the two
untested scheduleRetry guards: add a test using a non-PROCESSING job that
asserts the expected IllegalStateException message and unchanged PENDING status,
and a test using a claimed PROCESSING job with null nextRetryAt that asserts the
expected IllegalArgumentException message, unchanged PROCESSING status, and zero
retry count.
In
`@src/test/java/com/opensource/docgrid/domain/worker/config/IndexingWorkerPropertiesTest.java`:
- Around line 49-60: 보강된 retry delay 테스트에서 isRetryDelayValid의 경계값과 음수 입력을
고정하십시오. retryInitialDelay와 retryMaxDelay가 동일한 양수 Duration일 때 유효함을 단언하고,
retryInitialDelay가 음수일 때 유효하지 않음을 검증하십시오. 기존의 0 이하 및 역전된 최대 지연 검증은 유지하십시오.
In
`@src/test/java/com/opensource/docgrid/domain/worker/entity/EmbeddingJobAttemptTest.java`:
- Around line 103-112: Update the existing assertions in EmbeddingJobAttemptTest
around markFailed to also verify that the original failure duration is
preserved: assert attempt.getDurationMs() remains 2_000L after the repeated
failure request, alongside the existing endedAt and error assertions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: d68bb01d-58eb-47c6-8e52-0a211e2decf1
📒 Files selected for processing (31)
docs/design/Gimini-3-#88-document-indexing-failure-retry.mddocs/test-results/Gimini-3-#88-document-indexing-failure-retry.mdsrc/main/java/com/opensource/docgrid/domain/document/entity/DocumentVersion.javasrc/main/java/com/opensource/docgrid/domain/embedding/controller/IndexingJobAdminController.javasrc/main/java/com/opensource/docgrid/domain/embedding/converter/EmbeddingJobAttemptConverter.javasrc/main/java/com/opensource/docgrid/domain/embedding/dto/request/FailDocumentIndexingRequest.javasrc/main/java/com/opensource/docgrid/domain/embedding/dto/response/DocumentIndexingFailureResponse.javasrc/main/java/com/opensource/docgrid/domain/embedding/entity/EmbeddingJob.javasrc/main/java/com/opensource/docgrid/domain/embedding/enums/IndexingFailureType.javasrc/main/java/com/opensource/docgrid/domain/embedding/repository/EmbeddingJobRepository.javasrc/main/java/com/opensource/docgrid/domain/embedding/repository/EmbeddingRepository.javasrc/main/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureService.javasrc/main/java/com/opensource/docgrid/domain/embedding/service/command/EmbeddingJobClaimService.javasrc/main/java/com/opensource/docgrid/domain/worker/config/IndexingWorkerProperties.javasrc/main/java/com/opensource/docgrid/domain/worker/entity/EmbeddingJobAttempt.javasrc/main/java/com/opensource/docgrid/global/exception/ErrorCode.javasrc/main/java/com/opensource/docgrid/global/exception/GlobalExceptionHandler.javasrc/main/resources/application.ymlsrc/main/resources/db/migration/V35__add_embedding_job_next_retry_at.sqlsrc/test/java/com/opensource/docgrid/domain/document/entity/DocumentVersionTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/controller/IndexingJobAdminControllerTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/converter/EmbeddingJobAttemptConverterTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/dto/request/FailDocumentIndexingRequestTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/entity/EmbeddingJobTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/enums/IndexingFailureTypeTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/integration/DocumentIndexingFailureIntegrationTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/integration/EmbeddingJobClaimIntegrationTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/service/command/EmbeddingJobClaimServiceTest.javasrc/test/java/com/opensource/docgrid/domain/worker/config/IndexingWorkerPropertiesTest.javasrc/test/java/com/opensource/docgrid/domain/worker/entity/EmbeddingJobAttemptTest.java
| retry-initial-delay: ${INDEXING_WORKER_RETRY_INITIAL_DELAY:10s} | ||
| retry-max-delay: ${INDEXING_WORKER_RETRY_MAX_DELAY:5m} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## Locate relevant files"
git ls-files | rg '(^|/)(application(\..+)?\.(yml|yaml)|DocumentIndexingFailureServiceTest\.java|.*IndexingWorker.*)$' || true
echo
echo "## application.yml around indexing retry"
if [ -f src/main/resources/application.yml ]; then
nl -ba src/main/resources/application.yml | sed -n '1,80p' | rg -n -C 5 'indexing|retry-initial-delay|retry-max-delay|maxRetryCount|retry|job|worker' || true
fi
echo
echo "## Search relevant symbols"
rg -n "retry-initial-delay|retry-max-delay|maxRetryCount|IndexingWorkerProperties|DocumentIndexingFailureServiceTest|Retry" src/main src/test || true
echo
echo "## Candidate Java outlines/files"
fd -a 'IndexingWorker|DocumentIndexingFailure' src/main src/test 2>/dev/null || true
for f in $(git ls-files | rg '(IndexingWorker|DocumentIndexingFailure).*\.java$'); do
echo "--- $f"
wc -l "$f"
ast-grep outline "$f" || true
doneRepository: DocGrid/backend
Length of output: 33872
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import math
from pathlib import Path
import re
paths = {
"application": Path("src/main/resources/application.yml"),
"properties_test": Path("src/test/java/com/opensource/docgrid/domain/worker/config/IndexingWorkerPropertiesTest.java"),
"service_test": Path("src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.java"),
"integration_test": Path("src/test/java/com/opensource/docgrid/domain/embedding/integration/DocumentIndexingFailureIntegrationTest.java"),
"service": Path("src/main/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureService.java"),
}
for name, path in paths.items():
print(f"--- {name}: {path}")
s = path.read_text()
print(f" has_retry_config: {bool(re.search(r'([\\$]?indexing\\.worker\\.(retry-initial-delay|retry-max-delay)|INDEXING_WORKER_(RETRY_INITIAL_DELAY|RETRY_MAX_DELAY))', s, re.I))}")
print(f" relevant snippets:")
for i, line in enumerate(s.splitlines(), 1):
if any(tok in line for tok in [
"retry-initial-delay", "retry-max-delay",
"INDEXING_WORKER_RETRY", "DEFAULT_RETRY", "ofSeconds", "ofMinutes",
"40s", "40秒", "40 초", "5m", "5 분", "5 minutes",
"fail_capsRetryBackoffAtMaximumDelay", "fail_doublesRetryDelay",
"calculateRetryDelay"
]):
print(f" {i}: {line}")
print()
def retry_delay(retry_count, initial, max_delay, max_retry_count):
if retry_count == 0:
return 0
for i in range(retry_count):
pass
delay = min(initial, max_delay)
for attempt in range(retry_count - 1):
delay = min(delay * 2, max_delay)
return delay
initial = 10
for max_delay in [40, 300]:
print(f"max_delay={max_delay}s table:")
for max_retry_count in [3, 4, 5];
print(f" maxRetryCount={max_retry_count}, retryable_count={max_retry_count}, last_delay_s={retry_delay(max_retry_count, initial, max_delay, max_retry_count)}")
PY
echo
echo "## Exact retry delay implementation"
nl -ba src/main/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureService.java | sed -n '360,395p'
echo
echo "## Configuration property defaults and tests"
nl -ba src/main/resources/application.yml | sed -n '20,32p' 2>/dev/null || sed -n '20,32p' src/main/resources/application.yml
nl -ba src/test/java/com/opensource/docgrid/domain/worker/config/IndexingWorkerPropertiesTest.java | sed -n '38,48p'
nl -ba src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.java | sed -n '84,182p'
nl -ba src/test/java/com/opensource/docgrid/domain/embedding/integration/DocumentIndexingFailureIntegrationTest.java | sed -n '68,82p'Repository: DocGrid/backend
Length of output: 614
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import math
import re
from pathlib import Path
paths = {
"application": Path("src/main/resources/application.yml"),
"properties_test": Path("src/test/java/com/opensource/docgrid/domain/worker/config/IndexingWorkerPropertiesTest.java"),
"service_test": Path("src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.java"),
"integration_test": Path("src/test/java/com/opensource/docgrid/domain/embedding/integration/DocumentIndexingFailureIntegrationTest.java"),
"service": Path("src/main/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureService.java"),
}
for name, path in paths.items():
s = path.read_text()
print(f"--- {name}: {path}")
has = bool(re.search(
r'([\\$]?indexing\.worker\.(retry-initial-delay|retry-max-delay)|INDEXING_WORKER_(RETRY_INITIAL_DELAY|RETRY_MAX_DELAY))',
s,
re.I,
))
print(f" has_retry_config: {has}")
print(f" relevant snippets:")
for i, line in enumerate(s.splitlines(), 1):
if any(tok in line for tok in [
"retry-initial-delay", "retry-max-delay",
"INDEXING_WORKER_RETRY", "DEFAULT_RETRY", "ofSeconds", "ofMinutes",
"40s", "5m",
"fail_capsRetryBackoffAtMaximumDelay", "fail_doublesRetryDelay",
"calculateRetryDelay"
]):
print(f" {i}: {line}")
print()
initial = 10
for max_delay in [40, 300]:
print(f"max_delay={max_delay}s table:")
for max_retry_count in [3, 4, 5]:
delay = min(initial, max_delay)
for attempt in range(max_retry_count - 1):
delay = min(delay * 2, max_delay)
print(f" maxRetryCount={max_retry_count}, last_delay_s={delay}")
PY
echo
echo "## Exact retry delay implementation"
nl -ba src/main/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureService.java | sed -n '360,395p'
echo
echo "## Configuration property defaults and tests"
nl -ba src/main/resources/application.yml | sed -n '20,32p'
nl -ba src/test/java/com/opensource/docgrid/domain/worker/config/IndexingWorkerPropertiesTest.java | sed -n '38,48p'
nl -ba src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.java | sed -n '84,182p'
nl -ba src/test/java/com/opensource/docgrid/domain/embedding/integration/DocumentIndexingFailureIntegrationTest.java | sed -n '68,82p'Repository: DocGrid/backend
Length of output: 2692
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
for path, ranges in [
("src/main/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureService.java", [(379, 396)]),
("src/main/java/com/opensource/docgrid/domain/worker/config/IndexingWorkerProperties.java", [(26, 82)]),
("src/test/java/com/opensource/docgrid/domain/worker/config/IndexingWorkerPropertiesTest.java", [(38, 48), (54, 59)]),
]:
s = Path(path).read_text()
lines = s.splitlines()
print(f"--- {path}")
for start, end in ranges:
for i in range(start, min(end, len(lines))+1):
print(f"{i}: {lines[i-1]}")
print()
PYRepository: DocGrid/backend
Length of output: 4071
운영 기본 Retry Backoff 정책과 테스트 설정을 맞춰세요.
application.yml의 기본값은 10s와 5m이지만, DocumentIndexingFailureServiceTest와 통합 테스트는 40s를 상한으로 검증합니다. maxRetryCount가 4 이상이면 5분 상한에서 80초·160초 지연까지 사용할 수 있어, 고정 10s-20s-40s 정책이라면 retry-max-delay도 40s로 통합해야 합니다. 5분 상한이 의도라면 해당 정책을 명시하고 관련 테스트를 그 동작에 맞게 확장하세요.
src/main/resources/application.yml#L27-L28
src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.java#L88-L90
📍 Affects 2 files
src/main/resources/application.yml#L27-L28(this comment)src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.java#L88-L90
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/resources/application.yml` around lines 27 - 28, 운영 기본 Retry Backoff
정책을 테스트와 일치시키세요. src/main/resources/application.yml 27-28행의 retry-max-delay를 고정
10s-20s-40s 정책에 맞게 40s로 조정하고,
src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.java
88-90행의 검증도 동일한 상한을 사용하도록 정리하세요. 5분 상한을 유지해야 한다면 해당 정책에 맞춰 두 위치의 테스트 기대값과 지연 검증을
확장하세요.
Source: Path instructions
변경 사항
embedding_jobs.next_retry_at과 실행 가능 시각 기반 Queue 조회 조건을 추가했습니다.영향
일시적인 저장소·Embedding Provider·Worker 장애는 즉시 Job을 종료하지 않고 예약 시각 이후 기존 Claim Queue에서 다시 처리됩니다. 데이터 또는 상태 불변식 오류는 즉시 최종 실패하며, 기존에 검색 가능했던 문서는 새 Version 실패의 영향을 받지 않습니다.
검증
./gradlew test: 514개 통과./gradlew claimConcurrencyTest: 2개 통과Closes #88