Skip to content

fix(v2ray): race-free config cleanup, replace fixed 2s setTimeout#22

Merged
Sentinel-Bluebuilder merged 1 commit intomasterfrom
fix/v2ray-config-cleanup
Apr 27, 2026
Merged

fix(v2ray): race-free config cleanup, replace fixed 2s setTimeout#22
Sentinel-Bluebuilder merged 1 commit intomasterfrom
fix/v2ray-config-cleanup

Conversation

@Sentinel-Bluebuilder
Copy link
Copy Markdown
Owner

Summary

The V2Ray config at <tmpdir>/sentinel-v2ray/config.json contains the per-session UUID and was being deleted by a fixed setTimeout(..., 2000) right after spawn(). Two problems with that:

1. Race against the next loop iteration. cfgPath is the same path every attempt (config.json, not unique-per-attempt). If outbound A's V2Ray dies fast and the loop iterates to outbound B which overwrites cfgPath, the stale 2s timer from A then deletes B's freshly-written running config. Hard to repro, but real.

2. Dangling timer holds the event loop open if the process exits in the gap before it fires.

Fix

connection/tunnel.js:563-583

Replace the unconditional 2s timer with:

  • An idempotent deleteCfg() guarded by cfgDeleted
  • proc.once('exit', deleteCfg) so the cfg is removed when V2Ray dies (covers fast-fail path)
  • Inline deleteCfg() right after waitForPort(...) succeeds — at that point V2Ray has fully parsed the config
  • A 5s unref()'d safety-net setTimeout for the edge case where neither happens before abort

Windows note: V2Ray may still have the file open when unlink runs. The existing try { } catch {} swallows EBUSY, and the exit handler picks it up once the process dies. No regression vs. the old timer behaviour there.

Test plan

  • Connect to a V2Ray node, verify SOCKS5 proxy works
  • After connect, confirm <tmpdir>/sentinel-v2ray/config.json is gone
  • Disconnect, confirm cfg is gone (was already covered by old code)
  • Force a fast-fail outbound (e.g., wrong UUID): cfg should still be gone after the loop completes
  • Abort mid-handshake (Ctrl+C / signal disconnect): no leaked cfg, no leaked timer

The V2Ray config file at <tmp>/sentinel-v2ray/config.json contains the
session UUID. Old code deleted it via a fixed 2s setTimeout right after
spawn(). Two problems:

1. Race against next loop iteration. cfgPath is the SAME path every attempt
   (config.json, not config.<n>.json). If outbound A's V2Ray fails fast and
   the loop advances to outbound B which overwrites cfgPath in <2s, the
   STALE 2s timer from A then deletes B's running config.

2. Pending timer holds the event loop open if the process exits before
   the timer fires.

Fix: delete the moment V2Ray has demonstrably loaded the config (SOCKS
port is up) OR when the process exits, whichever first. A 5s unref'd
safety-net timer handles the edge case where neither happens before
abort. Idempotent guard (cfgDeleted) prevents double-unlink warnings.

On Windows, V2Ray may still have the file open when unlink runs — the
existing try/catch swallows EBUSY, and the exit handler picks it up
once the proc dies. No regression vs. the old timer there.
@Sentinel-Bluebuilder Sentinel-Bluebuilder merged commit 3bff2f2 into master Apr 27, 2026
2 checks passed
@Sentinel-Bluebuilder Sentinel-Bluebuilder deleted the fix/v2ray-config-cleanup branch April 27, 2026 09:11
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.

1 participant