fix(nextflow): don't mark workspace scan flushed when both probes fail

_flush_deferred_workspace_scan sets _workspace_scan_flushed unconditionally after its
two completion() flush attempts, even when both raised. A later find_referencing_symbols
call then silently skips the flush and answers from a possibly-incomplete workspace AST
cache for the rest of the session, with no exception and no retry.

Fixes #1871
This commit is contained in:
Amir Fathi committed 2026-08-15 19:05:13 +00:00
1 parent 93ec043105
commit c72c07ae29
3 files changed
+71 -1

No files matched your search

+3
View File
@@ -7,6 +7,9 @@ Status of the `main` branch. Changes prior to the next official version change w
project list in `serena_config.yml`
* Language Servers:
- Fix: Nextflow's `_flush_deferred_workspace_scan` marked the workspace scan flushed even when both
of its `completion` probes failed, permanently skipping the flush (and silencing retries) for the
rest of the session (#1871)
- Fix: Dart's `$/analyzerStatus` notifications were logged as unhandled-method warnings during analysis (#1855)
- Fix: Scala cross-file queries waited a fixed 5s after the first file was opened, which on a cold
Metals is long before its build import, indexing and compilation have finished; the first
@@ -320,12 +320,14 @@ class NextflowLanguageServer(SolidLanguageServer):
"textDocument": {"uri": self._resolve_file_uri(relative_file_path)},
"position": {"line": 0, "character": 0},
}
flushed = False
for _ in range(2):
try:
self.server.send.completion(params)
flushed = True
except Exception as e:
log.debug("Completion request used to flush the Nextflow workspace scan failed: %s", e)
self._workspace_scan_flushed = True
self._workspace_scan_flushed = flushed
@override
def _send_references_request(self, relative_file_path: str, line: int, column: int) -> list[lsp_types.Location] | None:
@@ -0,0 +1,65 @@
"""Regression test for the Nextflow deferred-workspace-scan flush flag.
``_flush_deferred_workspace_scan`` sends two ``completion`` requests purely to force the
server's debounced workspace scan, discarding their results; ``_workspace_scan_flushed``
exists only to skip that work once it is known to have happened. If both requests raise,
nothing was actually flushed and the flag must stay clear so the next call retries,
without spawning a real language server process.
"""
from solidlsp.language_servers.nextflow_language_server import NextflowLanguageServer
class _FakeCompletionSender:
def __init__(self, *, always_raise: bool = False) -> None:
self.calls = 0
self._always_raise = always_raise
def completion(self, params: dict) -> None:
self.calls += 1
if self._always_raise:
raise TimeoutError("no response from the Nextflow language server")
class _FakeServer:
def __init__(self, sender: _FakeCompletionSender) -> None:
self.send = sender
def _bare_nextflow_ls(sender: _FakeCompletionSender, repo_path: str) -> NextflowLanguageServer:
"""Create an instance without running __init__ (no JVM, no process), setting only the
state the flush machinery touches; same technique as test_typescript_timeout_policy.py.
"""
ls = object.__new__(NextflowLanguageServer)
ls.repository_root_path = repo_path
ls._workspace_scan_flushed = False
ls.server = _FakeServer(sender)
return ls
def test_flag_stays_clear_when_both_completion_calls_fail(tmp_path) -> None:
sender = _FakeCompletionSender(always_raise=True)
ls = _bare_nextflow_ls(sender, str(tmp_path))
ls._flush_deferred_workspace_scan("main.nf")
assert sender.calls == 2
assert ls._workspace_scan_flushed is False
# a later call must retry, not silently skip forever
ls._flush_deferred_workspace_scan("main.nf")
assert sender.calls == 4
def test_flag_is_set_when_a_completion_call_succeeds(tmp_path) -> None:
sender = _FakeCompletionSender(always_raise=False)
ls = _bare_nextflow_ls(sender, str(tmp_path))
ls._flush_deferred_workspace_scan("main.nf")
assert sender.calls == 2
assert ls._workspace_scan_flushed is True
# once flushed, a later call is a no-op
ls._flush_deferred_workspace_scan("main.nf")
assert sender.calls == 2