Skip to content

fix(symbol): сделать WorkspaceSymbolIndex синглтоном (#4123)#4125

Merged
nixel2007 merged 1 commit into
developfrom
fix/workspace-symbol-scope-context
Jun 15, 2026
Merged

fix(symbol): сделать WorkspaceSymbolIndex синглтоном (#4123)#4125
nixel2007 merged 1 commit into
developfrom
fix/workspace-symbol-scope-context

Conversation

@nixel2007

@nixel2007 nixel2007 commented Jun 15, 2026

Copy link
Copy Markdown
Member

Проблема

workspace/symbol стабильно падает с -32603 Internal error (issue #4123):

ScopeNotActiveException: ... 'scopedTarget.workspaceSymbolIndex':
Scope 'workspace' is not active for the current thread

Запрос выполняется на потоке workspaceServiceExecutor, которому JSON-RPC диспетчер не устанавливает workspace-контекст, а WorkspaceSymbolIndex был @WorkspaceScope → scoped proxy не резолвится.

Регресс rc.1 → rc.2: в rc.1 индекса ещё не было — workspace/symbol шёл обходом документов и работал кросс-воркспейсно. Индекс появился в rc.2 уже @WorkspaceScope, что и сломало запрос.

Решение

Снят @WorkspaceScope — индекс стал обычным синглтоном.

Обоснование, почему scope здесь лишний:

  • workspace/symbol по протоколу LSP — кросс-воркспейсный запрос: единый индекс по всем рабочим областям это и есть желаемое поведение (как в rc.1), изолировать области в выдаче не нужно;
  • индекс самодостаточен: index()/search() не обращаются ни к одному @WorkspaceScope-бину, workspace-контекст потока ему не нужен;
  • жизненный цикл держится на per-document событиях (Changed/Cleared/Closed/Removed); removeWorkspace штатно рассылает ServerContextDocumentRemovedEvent по каждому документу → закрытие/удаление области вычищает её документы без per-workspace teardown'а;
  • индекс уже потокобезопасен (ReadWriteLock + ConcurrentMap), конкурентная индексация из populate-пулов разных областей корректна.

SymbolProvider и BSLWorkspaceService остаются без изменений относительно develop — провайдер просто дёргает один индекс.

Тесты

  • Регрессионный тест BSLWorkspaceServiceTest#symbol_worksFromThreadWithoutWorkspaceContext: воспроизводит прод-условие (вызывающий поток без workspace-контекста). До фикса падал с ScopeNotActiveException, после — зелёный.
  • WorkspaceSymbolIndexTest, SymbolProvider*Test, BSLWorkspaceServiceTest проходят (тестовый liteCleanup чистит синглтон-индекс через те же document-события).

Closes #4123

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

SymbolProvider is refactored to inject ServerContextProvider and rewrites getSymbols() to iterate all registered workspace contexts, activating WorkspaceContextHolder.forUri() for each before collecting symbols via the new extracted method collectWorkspaceSymbols(). Unit tests are updated to the new constructor signature and API, and a new integration test in BSLWorkspaceServiceTest verifies that workspace context is properly initialized during workspace/symbol handling.

Changes

workspace/symbol ScopeNotActiveException fix

Layer / File(s) Summary
SymbolProvider: per-workspace context activation and method extraction
src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/SymbolProvider.java
Injects ServerContextProvider; rewrites getSymbols() to loop over all contexts, skip null workspace URIs, and activate WorkspaceContextHolder.forUri() before collecting; extracts per-workspace search into collectWorkspaceSymbols(); updates class Javadoc.
Unit test adaptations: constructor wiring and call sites
src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/SymbolProviderTest.java, src/test/java/.../SymbolProviderStreamingTest.java, src/test/java/.../SymbolProviderScriptVariantTest.java
Adds mocked ServerContextProvider to SymbolProvider constructor in all unit tests; seeds WorkspaceContextHolder in before(); switches all getSymbols() invocations to collectWorkspaceSymbols() across streaming, cancellation, fuzzy, and script-variant scenarios.
Integration test: workspace context initialized during workspace/symbol
src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLWorkspaceServiceTest.java
Adds a test that clears WorkspaceContextHolder, calls workspaceService.symbol(), and asserts the expected procedure symbol is returned, reproducing and verifying the end-to-end fix.

Sequence Diagram

sequenceDiagram
  participant Client
  participant BSLWorkspaceService
  participant SymbolProvider
  participant ServerContextProvider
  participant WorkspaceContextHolder
  participant WorkspaceSymbolIndex

  Client->>BSLWorkspaceService: symbol(WorkspaceSymbolParams)
  BSLWorkspaceService->>SymbolProvider: getSymbols(params, cancelChecker)
  SymbolProvider->>ServerContextProvider: getAllContexts()
  ServerContextProvider-->>SymbolProvider: Map of ServerContext
  loop each ServerContext with non-null workspaceUri
    SymbolProvider->>WorkspaceContextHolder: forUri(workspaceUri)
    SymbolProvider->>SymbolProvider: collectWorkspaceSymbols(params, cancelChecker)
    SymbolProvider->>WorkspaceSymbolIndex: search(params)
    WorkspaceSymbolIndex-->>SymbolProvider: symbols for workspace
  end
  SymbolProvider-->>BSLWorkspaceService: aggregated symbols
  BSLWorkspaceService-->>Client: Either.forRight(symbols)
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • 1c-syntax/bsl-language-server#4105: Introduced the workspace/symbol feature that delegates symbol lookup to WorkspaceSymbolIndex inside SymbolProvider, which is the exact component this PR fixes for workspace-scoped context activation.
  • 1c-syntax/bsl-language-server#4094: Modified SymbolProvider.getSymbols() and its call chain to add CancelChecker cancellation support, which is directly touched by this PR's refactoring of the same method.
  • 1c-syntax/bsl-language-server#4003: Alters ServerContextProvider, the newly injected dependency in SymbolProvider that this PR uses to enumerate workspace contexts.

Suggested labels

hacktoberfest-accepted

Suggested reviewers

  • sfaqer

Poem

🐇 Hopping through scopes, oh what a fright,
The workspace was missing — symbols took flight!
Now contexts are set before each little search,
No more ScopeNotActive left in the lurch.
Every workspace is found, every symbol returns,
The bunny of fixes keeps learning and learns!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ⚠️ Warning The title 'fix(symbol): сделать WorkspaceSymbolIndex синглтоном (#4123)' is partially related to the changeset. It references 'singleton' for WorkspaceSymbolIndex, but the actual fix does not make WorkspaceSymbolIndex a singleton. The changes focus on iterating through all workspace contexts and setting workspace context before accessing the index, not converting it to a singleton. Update the title to accurately describe the actual implementation: something like 'fix(symbol): set workspace context for workspace-scoped symbol indexing' to reflect that the solution establishes workspace context across all registered contexts rather than making WorkspaceSymbolIndex a singleton.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed All code changes comprehensively address issue #4123: SymbolProvider now iterates workspaces via ServerContextProvider and sets WorkspaceContextHolder before accessing workspace-scoped beans, fixing ScopeNotActiveException.
Out of Scope Changes check ✅ Passed All changes are in-scope: SymbolProvider refactoring to support multi-workspace context iteration, test updates reflecting the new internal method call pattern, and regression test verifying the fix.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/workspace-symbol-scope-context

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results

 3 432 files  ±0   3 432 suites  ±0   1h 41m 7s ⏱️ + 6m 32s
 3 405 tests +1   3 387 ✅ +1   18 💤 ±0  0 ❌ ±0 
20 430 runs  +6  20 322 ✅ +6  108 💤 ±0  0 ❌ ±0 

Results for commit 48ad28c. ± Comparison against base commit b0d3bfc.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/SymbolProviderTest.java`:
- Around line 79-82: The WorkspaceContextHolder is set in the test setup but
never restored, causing context leakage across tests. Add a cleanup method
(using `@After` annotation for JUnit 4 or `@AfterEach` for JUnit 5) that restores
the WorkspaceContextHolder to its previous state by calling the appropriate
reset or clear method on WorkspaceContextHolder. This should be paired with the
setup code where WorkspaceContextHolder.set() is called to ensure the holder is
properly cleaned up after each test execution.
🪄 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

Run ID: 06d53217-25e4-42bd-aaf4-9d47619c904b

📥 Commits

Reviewing files that changed from the base of the PR and between 48ad28c and bb31fd7.

📒 Files selected for processing (4)
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/SymbolProvider.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/SymbolProviderScriptVariantTest.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/SymbolProviderStreamingTest.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/SymbolProviderTest.java

Comment on lines 79 to 82
// Индекс символов — workspace-scoped: наполняем его под контекстом этого workspace,
// чтобы getSymbols, обходящий getAllContexts(), нашёл символы в его индексе.
WorkspaceContextHolder.set(workspaceContext.getWorkspaceUri());
workspaceContext.populateContext();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Restore workspace context after test setup to avoid leakage

Line 81 sets WorkspaceContextHolder but never restores it. This can leak context across tests and make failures order-dependent.

Suggested fix
-    WorkspaceContextHolder.set(workspaceContext.getWorkspaceUri());
-    workspaceContext.populateContext();
+    try (var ignored = WorkspaceContextHolder.forUri(workspaceContext.getWorkspaceUri())) {
+      workspaceContext.populateContext();
+    }
🤖 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/github/_1c_syntax/bsl/languageserver/providers/SymbolProviderTest.java`
around lines 79 - 82, The WorkspaceContextHolder is set in the test setup but
never restored, causing context leakage across tests. Add a cleanup method
(using `@After` annotation for JUnit 4 or `@AfterEach` for JUnit 5) that restores
the WorkspaceContextHolder to its previous state by calling the appropriate
reset or clear method on WorkspaceContextHolder. This should be paired with the
setup code where WorkspaceContextHolder.set() is called to ensure the holder is
properly cleaned up after each test execution.

workspace/symbol падал с ScopeNotActiveException: индекс был @WorkspaceScope,
а запрос выполняется на потоке workspaceServiceExecutor без установленного
JSON-RPC диспетчером workspace-контекста, поэтому scoped proxy не резолвился.
Регресс rc.1 → rc.2: в rc.1 индекса не было (workspace/symbol шёл обходом
документов и работал кросс-воркспейсно), индекс появился в rc.2 уже scoped.

workspace/symbol по протоколу LSP — кросс-воркспейсный запрос, а индекс
самодостаточен (не обращается ни к одному workspace-scoped бину) и держит
жизненный цикл на per-document событиях, поэтому workspace-scope был лишним
и только ломал доступ с потока без контекста. Снят: индекс — обычный singleton
с единым trie по всем рабочим областям; закрытие/удаление области штатно
вычищает её документы через ServerContextDocumentRemovedEvent. SymbolProvider и
BSLWorkspaceService остаются без изменений относительно develop.

Добавлен регрессионный тест: workspace/symbol обслуживается с потока без
workspace-контекста.

Closes #4123

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@nixel2007
nixel2007 force-pushed the fix/workspace-symbol-scope-context branch from f781679 to aaa81c7 Compare June 15, 2026 16:36
@nixel2007 nixel2007 changed the title fix(symbol): установить workspace-контекст в workspace/symbol fix(symbol): сделать WorkspaceSymbolIndex синглтоном (#4123) Jun 15, 2026
@nixel2007
nixel2007 merged commit 3ec2a97 into develop Jun 15, 2026
33 checks passed
@nixel2007
nixel2007 deleted the fix/workspace-symbol-scope-context branch June 15, 2026 16:51
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] workspace/symbol падает с ScopeNotActiveException (scopedTarget.workspaceSymbolIndex) в 1.0.0-rc.2

1 participant