fix(qdrant): keep GitHub collection discovery pending after a validation interrupt - #243
Open
detail-app[bot] wants to merge 1 commit into
Conversation
…ion interrupt An InterruptedException raised while validating a GitHub collection was converted to an IllegalStateException and fell through attemptDiscovery's catch (RuntimeException) arm, permanently parking the state machine at FAILED. The listing path already propagated the same interrupt as a checked exception and stayed PENDING, so the two halves of loadValidatedGitHubCollections handled one transient event in two non-equivalent ways, and the non-PENDING guard then short-circuited every @scheduled retry with no in-bean recovery. - declare throws InterruptedException on validateGitHubCollection and drop the local catch that rethrew it as IllegalStateException, so the interrupt reaches attemptDiscovery's existing catch (InterruptedException) and keeps state PENDING like the listing path, with the interrupt status still restored
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Detail bug report: View on Detail
Closes #230
Bug
QdrantGitHubCollectionDiscovery.validateGitHubCollectioncaughtInterruptedExceptionand rethrew it as a plainIllegalStateException, which fell throughattemptDiscovery'scatch (RuntimeException)arm and permanently parked the discovery state machine atFAILED. The listing path already propagated the same interrupt as a checked exception and stayedPENDING, so the two halves ofloadValidatedGitHubCollectionshandled one transient event in two non-equivalent ways. OnceFAILED, the non-PENDINGguard short-circuited every@Scheduledretry, leaving the retrieval fan-out (getDiscoveredCollections()) and readiness (discoveryHealth()) stuck empty/DOWNfor the bean's lifetime and emitting a spuriousERRORunder the "schema validation failed" banner. This was a regression introduced when thePENDING/READY/FAILEDstate machine was added.Fix
Declare
throws InterruptedExceptiononvalidateGitHubCollectionand delete the localcatch (InterruptedException)that rethrew it asIllegalStateException. The interrupt now propagates as a checked exception — exactly like the listing path — intoattemptDiscovery's existingcatch (InterruptedException)arm, which restores the interrupt status and keeps the statePENDINGso the@Scheduledretry (or next startup) can recover. This is the idiomatic fix because it restores symmetry between the listing and validation halves and reuses the existing transient-interrupt handler rather than adding a new one.Testing
Three committed unit tests pin the fix against regression:
PENDING(notFAILED), cancels the in-flightgetCollectionInfoAsyncfuture, and reportsDOWN/"pending";@Scheduledretry entry point recovers and reachesREADYonce Qdrant returns valid collection info — the key guard against the stuck-FAILEDno-recovery path;Existing tests still pass unchanged, including schema-mismatch →
FAILED(fail-closed preserved), transient gRPC failure →PENDING+ recover-on-retry, listing timeout →PENDING, the inventory refresh path (independent ofdiscoveryState), and the happy-path discovery of a valid collection.Routine checks all pass: full JVM unit-test suite (no new failures, no errors),
compileJava/compileTestJava, SpotBugs and PMD (main + test), Spotless/Palantir formatting, ast-grep Java rules, the Ruby chat-model SSOT guard, andmake build,make lint, andmake test(16 shell contracts + the JVM suite).End-to-end: booted the packaged jar on Java 25 (BellSoft Liberica). With Qdrant down, discovery logged the transient
WARN ... deferred: Qdrant is unavailable(not a schema-failureERROR) and readiness reportedDOWN/pending. With Qdrant 1.18.3 up viadocker compose, discovery reachedREADY(the "No GitHub collections found"INFOline fires only afterdiscoveryState.set(READY)), and the shutdown log contained noschema validation failed/validation interruptedline. The Qdrant 1.18.3 integration contract script also passed, exercising the samelistCollectionsAsync+getCollectionInfoAsyncpath against a real Qdrant.A real
Thread.interrupt()landing mid-Future.get()in a live scheduler thread is timing-dependent, so the committed tests stubget(...)to throwInterruptedExceptionto exercise that code arm deterministically; the live trigger is realistically only a context-closeshutdownNow()during an in-flight@Scheduledretry, where the JVM is exiting.Automatic Fixes PRs can be configured here.