Repository navigation
Fix listener error swallowing (#1990), SyncContext double-close (#1992), and test flakiness (#1350) - #2108
Conversation
…ng, sync context double-close and derandomize tests - apache#1990: Log listener exceptions in ChainedRepositoryListener and ChainedTransferListener; add unit tests for multicast resilience. - apache#1992: Prevent SyncContext double-close in DefaultArtifactResolver and DefaultMetadataResolver; add verification test. - apache#1350: Derandomize GenericVersionTest.testCompareUuidRandom with fixed seed.
gnodet
left a comment
There was a problem hiding this comment.
Two confirmed resource leaks (HIGH) in DefaultArtifactResolver and DefaultMetadataResolver where removing try-with-resources creates a gap: if the second syncContextFactory.newInstance() call throws, the first shared SyncContext is never closed. The original code handled this correctly via try-with-resources semantics. The test for the SyncContext fix is technically valid but misleading — it uses a single SyncContext instance for both shared and exclusive roles, making the assertion comment inaccurate.
The listener error handling improvement and test derandomization are sound.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
gnodet
left a comment
There was a problem hiding this comment.
Two confirmed resource leaks (HIGH) in DefaultArtifactResolver and DefaultMetadataResolver where removing try-with-resources creates a gap: if the second syncContextFactory.newInstance() call throws, the first shared SyncContext is never closed. The original code handled this correctly via try-with-resources semantics. The test for the SyncContext fix is technically valid but misleading — it uses a single SyncContext instance for both shared and exclusive roles, making the assertion comment inaccurate.
The listener error handling improvement and test derandomization are sound.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
Review follow-up: the shared context was created outside any try block, so a SyncContextFactory that throws while creating the exclusive context leaked it. The request loop now runs before either context is created, and the shared context is closed if the exclusive one cannot be obtained. The shared-to-exclusive hand-over reassigns before closing so a throwing close() cannot leave the shared context to be closed twice. The lifecycle test uses distinct instances for the two roles.
…faultMetadataResolver
gnodet
left a comment
There was a problem hiding this comment.
Re-review after follow-up commits (0d76d59, a9d1d5c). All previous findings are addressed:
-
✅ Resource leak (HIGH) — DefaultArtifactResolver: Restored try-with-resources using
CloseOnceSyncContextwrapper. The creation window is now safe: ifnewInstance(session, false)throws, try-with-resources closes the shared context. TheCloseOnceSyncContextcorrectly delegatesclose()at most once, and theresolve()finally block properly handles the case wherecurrent == shared(closes exclusive too via nested try-finally). -
✅ Resource leak (HIGH) — DefaultMetadataResolver: Same fix applied symmetrically.
-
✅ Misleading test (MEDIUM): Now uses two distinct counting instances dispatched by the
sharedflag, each asserted closed exactly once. NewtestSharedSyncContextIsClosedWhenExclusiveCannotBeCreatedtest directly covers the resource leak scenario. Test also added forDefaultMetadataResolver. -
✅ JUL imports (LOW): Fully-qualified class names replaced with proper imports. JUL deliberately kept since
maven-resolver-utilhas no SLF4J dependency — reasonable tradeoff.
The CloseOnceSyncContext wrapper is well designed: package-private, clear Javadoc, IllegalStateException on acquire-after-close. The closed field correctly omits volatile since SyncContext is single-threaded by contract.
Note: No milestone is set — this should target 2.0.23.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
The "close once" pattern is using AtomicBoolean in resolver. Also make sure that the only SyncContext close method is idempotent
|
Applied two changes:
|
Summary of Fixes
ChainedRepositoryListenerandChainedTransferListenernow log exceptions from listeners at WARNING level inhandleError()instead of silently swallowing them. Added unit tests verifying that an exception in one listener does not disrupt delivery to subsequent listeners in the multicast chain.DefaultArtifactResolverandDefaultMetadataResolverto eliminate redundant internal/finallySyncContext.close()calls, ensuringSyncContextinstances are closed strictly once. Added unit testtestSyncContextIsClosedExactlyOnceverifying single-close lifecycle.RandominGenericVersionTest.testCompareUuidRandomwith a fixed seed to ensure deterministic, reproducible test runs across CI environments.