apache / apache/netbeans

lsp.client: multi-mime LanguageServerProvider class registrations start one server process per MIME (reuse map is instance-keyed)

Open
#9,581 1 comment 0 reactions 0 assignees View on GitHub
LSP
Dominant language
Java
Stars
3.1k
Forks
935
Avg merge
2d 3h
Merged PRs (30d)
17

Description

### Apache NetBeans version

Apache NetBeans 25 (observed on RELEASE300, still present on RELEASE310)

### Bug description

**Summary:** When one `LanguageServerProvider` is registered for multiple MIME types with a class-level `@MimeLookup.Registration` / layer class registration, `LSPBindings` starts **one language-server process per MIME type** instead of reusing the running server, because its server-reuse map is keyed by provider **instance** — and a class registration places a separate `.instance` in each mime folder, each instantiated independently.

**Measured effect** (in a NetBeans-Platform-based IDE using ide/lsp.client, with providers registered for both `text/javascript` and `text/typescript`):

- two `typescript-language-server` processes for a single mixed JS/TS project,
- two `deno lsp` processes for one deno workspace,
- two `ngserver` processes in an Angular project with a component (.ts) and its template open.

Each extra process is a full tsserver-class JVM/node footprint per project, silently.

**Mechanism** (from reading the RELEASE300/310 `LSPBindings` source/bytecode): `buildBindings` files a started server under every declared mime **only when the same provider instance is presented for each mime folder**. With a class-level registration, the second mime folder resolves a *different instance* of the same provider class, misses the reuse map, and a second server process is spawned. Shutdown being GC-driven (`LSPReference` + keep-alive) means both processes then live for the session.

**Workaround we ship:** converting every multi-mime provider registration to a static singleton factory method (`methodvalue` registration), so every mime folder resolves the same object. That fixes it completely — A/B measured 2 processes → 1 — but the requirement is undocumented and very easy to violate (we re-introduced it once via a three-mime CSS provider before gating registrations structurally).

### Steps to reproduce

1. Register one `LanguageServerProvider` class for two mimes (e.g. `text/javascript` and `text/typescript`) with a plain class-level registration.
2. Open one file of each mime from the same project.
3. Observe two identical language-server processes for the project (e.g. `pgrep -fl typescript-language-server`).

### Expected behavior

One server process per project for a provider declared on multiple mimes — or, failing that, a documented requirement that multi-mime providers must be registered as singletons.

**Suggested fix directions:** key the reuse map by provider class (or by the provider's declared mime set), or have `MimeLookup` resolution for `LanguageServerProvider` treated as singleton-per-class in `LSPBindings`. Happy to provide more detail or test against a patch — we carry a structural test (`registrations == getMimeTypes()`, no class-instance backdoor) that could inform one upstream.

### Context

Found while building NMOX Studio (Apache-2.0, NetBeans-Platform based): https://github.com/NMOX/NMOX-Studio — details in our engineering ledger entry 83 (docs/engineering/tech-debt.md).

Contributor guide

Open the contributing guide

Research direction

Start by reading LSPBindings.buildBindings and the MimeLookup/layer registrations involved in resolving LanguageServerProvider instances. Reproduce the issue with one provider registered for text/javascript and text/typescript, then observe the processes with pgrep. Done means the same project uses one language-server process and a regression test covers multi-MIME registration and reuse.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
developer-experience, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.