-
Notifications
You must be signed in to change notification settings - Fork 121
Add logging and test coverage for document close race condition handling #3725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Important Review skippedBot user detected. To trigger a single review, invoke the You can disable this status message by setting the Comment |
Co-authored-by: nixel2007 <[email protected]>
Co-authored-by: nixel2007 <[email protected]>
Co-authored-by: nixel2007 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR enhances the document close race condition handling by adding diagnostic logging, extracting a timeout constant for consistency, and introducing test coverage for various document close scenarios. The changes improve observability when worker threads fail to terminate gracefully after shutdown.
Key Changes:
- Extracted hardcoded 1-second timeout into
AWAIT_FORCE_TERMINATIONconstant for reuse across multiple code paths - Added warning logs when document executors fail to terminate within timeout after
shutdownNow()(normal path, interrupt path, and re-interruption scenarios) - Added three new test cases covering document close with pending changes, active changes, and termination delays
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java |
Added AWAIT_FORCE_TERMINATION constant and warning logs for executor termination timeouts in the didClose() method |
src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentServiceTest.java |
Added three new test methods to verify document closure behavior with pending/active changes and executor termination |
| @Test | ||
| void didCloseAwaitTerminationCompletes() throws IOException { | ||
| // given - open a document | ||
| var textDocumentItem = getTextDocumentItem(); | ||
| var didOpenParams = new DidOpenTextDocumentParams(textDocumentItem); | ||
| textDocumentService.didOpen(didOpenParams); | ||
|
|
||
| var uri = textDocumentItem.getUri(); | ||
| var documentContext = serverContext.getDocumentUnsafe(uri); | ||
| assertThat(documentContext).isNotNull(); | ||
| assertThat(serverContext.isDocumentOpened(documentContext)).isTrue(); | ||
|
|
||
| // when - close the document (which should wait for executor to terminate) | ||
| var closeParams = new DidCloseTextDocumentParams(); | ||
| closeParams.setTextDocument(new TextDocumentIdentifier(uri)); | ||
| textDocumentService.didClose(closeParams); | ||
|
|
||
| // then - verify the document is properly closed | ||
| // The close should complete successfully even if executor needs time to terminate | ||
| assertThat(serverContext.isDocumentOpened(documentContext)).isFalse(); | ||
| } |
Copilot
AI
Jan 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test appears to be redundant with the existing didClose() test at line 183. Both tests simply open a document and immediately close it without any intervening changes. The test doesn't actually verify "executor termination delays" as mentioned in the PR description because there are no pending operations to delay termination.
Consider either removing this test or modifying it to actually test a scenario with delays (e.g., by mocking the DocumentChangeExecutor to simulate slow termination).
| @Test | ||
| void didCloseWithPendingChanges() throws IOException { | ||
| // given - open a document and make changes | ||
| var textDocumentItem = getTextDocumentItem(); | ||
| var didOpenParams = new DidOpenTextDocumentParams(textDocumentItem); | ||
| textDocumentService.didOpen(didOpenParams); | ||
|
|
||
| var documentContext = serverContext.getDocumentUnsafe(textDocumentItem.getUri()); | ||
| assertThat(documentContext).isNotNull(); | ||
| assertThat(serverContext.isDocumentOpened(documentContext)).isTrue(); | ||
|
|
||
| // when - submit multiple changes rapidly and then close immediately | ||
| var params = new DidChangeTextDocumentParams(); | ||
| var uri = textDocumentItem.getUri(); | ||
|
|
||
| for (int i = 0; i < 5; i++) { | ||
| params.setTextDocument(new VersionedTextDocumentIdentifier(uri, 2 + i)); | ||
| var range = Ranges.create(0, 0, 0, 0); | ||
| var changeEvent = new TextDocumentContentChangeEvent(range, "// Change " + i + "\n"); | ||
| List<TextDocumentContentChangeEvent> contentChanges = new ArrayList<>(); | ||
| contentChanges.add(changeEvent); | ||
| params.setContentChanges(contentChanges); | ||
| textDocumentService.didChange(params); | ||
| } | ||
|
|
||
| // then - close should wait for pending changes to complete | ||
| var closeParams = new DidCloseTextDocumentParams(); | ||
| closeParams.setTextDocument(new TextDocumentIdentifier(uri)); | ||
| textDocumentService.didClose(closeParams); | ||
|
|
||
| // verify the document is closed | ||
| assertThat(serverContext.isDocumentOpened(documentContext)).isFalse(); | ||
| } |
Copilot
AI
Jan 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests didCloseWithPendingChanges and didCloseDuringActiveChange may have race conditions. After submitting document changes with didChange(), the changes are processed asynchronously in the DocumentChangeExecutor's worker thread. The didClose() method should wait for these changes to complete, but the tests should verify that this waiting actually works correctly.
Consider using await() with atMost() (as done in other tests like didChangeIncremental() at line 116) to verify that the document changes were actually applied before closing. This would make the tests more robust and actually test the race condition handling rather than just testing that close completes.
| @Test | ||
| void didCloseDuringActiveChange() throws IOException { | ||
| // given - open a document | ||
| var textDocumentItem = getTextDocumentItem(); | ||
| var didOpenParams = new DidOpenTextDocumentParams(textDocumentItem); | ||
| textDocumentService.didOpen(didOpenParams); | ||
|
|
||
| var documentContext = serverContext.getDocumentUnsafe(textDocumentItem.getUri()); | ||
| assertThat(documentContext).isNotNull(); | ||
| assertThat(serverContext.isDocumentOpened(documentContext)).isTrue(); | ||
|
|
||
| // when - submit a change | ||
| var params = new DidChangeTextDocumentParams(); | ||
| var uri = textDocumentItem.getUri(); | ||
| params.setTextDocument(new VersionedTextDocumentIdentifier(uri, 2)); | ||
| var range = Ranges.create(0, 0, 0, 0); | ||
| var changeEvent = new TextDocumentContentChangeEvent(range, "// New content\n"); | ||
| List<TextDocumentContentChangeEvent> contentChanges = new ArrayList<>(); | ||
| contentChanges.add(changeEvent); | ||
| params.setContentChanges(contentChanges); | ||
| textDocumentService.didChange(params); | ||
|
|
||
| // then - close immediately while change may still be processing | ||
| var closeParams = new DidCloseTextDocumentParams(); | ||
| closeParams.setTextDocument(new TextDocumentIdentifier(uri)); | ||
| textDocumentService.didClose(closeParams); | ||
|
|
||
| // verify the document is closed | ||
| assertThat(serverContext.isDocumentOpened(documentContext)).isFalse(); | ||
| } |
Copilot
AI
Jan 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to didCloseWithPendingChanges, this test submits a change and immediately closes without verifying that the change processing would have completed. While the test verifies that didClose() completes successfully, it doesn't actually verify the race condition scenario where changes are actively processing.
Consider adding verification that the changes were actually applied, or add a small delay before closing to force the race condition scenario. This would more thoroughly test the synchronization logic in didClose().
Addressed review feedback on the document close race condition fix by improving observability and test coverage.
Changes
Extracted timeout constant: Added
AWAIT_FORCE_TERMINATIONconstant (1 second) for the post-shutdown termination wait, replacing hardcoded values in multiple locationsAdded diagnostic logging: Log warnings when worker threads fail to terminate within timeout after
shutdownNow(), including:Added test coverage for race condition scenarios:
All tests verify document closure using
ServerContext.isDocumentOpened()to confirm proper cleanup.Example
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.