Skip to content

feat: auto-restart crashed language server with exponential backoff#163

Open
you922 wants to merge 2 commits intodwgx:masterfrom
you922:feat/ls-auto-restart
Open

feat: auto-restart crashed language server with exponential backoff#163
you922 wants to merge 2 commits intodwgx:masterfrom
you922:feat/ls-auto-restart

Conversation

@you922
Copy link
Copy Markdown

@you922 you922 commented May 10, 2026

Summary

When a Windsurf language server instance crashes, the proxy now automatically respawns it after a brief backoff instead of leaving downstream requests hanging with ECONNRESET / ERR_HTTP2_CONNECT errors.

Problem

The language server binary occasionally crashes due to memory pressure, upstream API changes, or transient errors. Currently, the proxy logs the crash and cleans up — but all subsequent requests to that LS instance get connection errors until a manual restart or the next ensureLs() call from a new request.

Reported in #157 where LanguageServer fails to start and users are left with no working endpoint.

Solution

New scheduleLsRestart() function added to src/langserver.js:

  • Hooks into proc.on('exit') — intercepts the exit event and schedules a timed restart
  • Exponential backoff: 1s → 2s → 4s → 8s (configurable base delay)
  • Retry cap: max 3 attempts (configurable), prevents infinite loops on permanent errors
  • Per-key tracking: _restartAttempts Map prevents duplicate restart timers
  • .unref() timeouts: doesn't block Node.js process exit
  • getRestartStats(): exposes restart attempt counts for monitoring

Configuration

LS_AUTO_RESTART=1                   # Enable auto-restart (default: on)
LS_AUTO_RESTART_MAX_RETRIES=3       # Max retry attempts (default: 3)
LS_AUTO_RESTART_BASE_DELAY_MS=1000  # Base backoff delay in ms (default: 1000)

Set LS_AUTO_RESTART=0 to disable (restore previous behavior).

Backward Compatibility

  • Default is LS_AUTO_RESTART=1 (enabled) — this changes behavior but improves reliability
  • Set LS_AUTO_RESTART=0 for the exact pre-PR behavior
  • No API changes, no configuration file changes

Closes #157

Chen Jiangjiang added 2 commits May 10, 2026 17:03
When a language server instance crashes, the proxy now automatically
respawns it after a brief backoff instead of leaving downstream
requests hanging with ECONNRESET / ERR_HTTP2_CONNECT errors.

Implementation:
- scheduleLsRestart() in langserver.js with configurable exponential
  backoff (base: 1s → 2s → 4s → 8s)
- Per-key retry counter to prevent infinite loops on permanent errors
- Env-configurable: LS_AUTO_RESTART, LS_AUTO_RESTART_MAX_RETRIES,
  LS_AUTO_RESTART_BASE_DELAY_MS
- getRestartStats() for monitoring restart health
- All timeouts use .unref() to not block process exit

Configuration:
  LS_AUTO_RESTART=1                   # default: on
  LS_AUTO_RESTART_MAX_RETRIES=3       # default: 3
  LS_AUTO_RESTART_BASE_DELAY_MS=1000  # default: 1000ms

Fixes: dwgx#157
Added _intentionalShutdown Set to track LS instances being shut
down deliberately via stopLanguageServer() or restartLsForProxy().
Without this, the exit handler unconditionally fires scheduleLsRestart
for every killed process, spawning unwanted LS instances.

Changes:
- _intentionalShutdown Set prevents restart for intentional kills
- restartLsForProxy marks key before process.kill
- stopLanguageServer marks all keys before kill loop
- Exit handler checks Set before calling scheduleLsRestart
- Cleanup after exit check (prevents set growth)
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] LanguageServer启动失败

1 participant