Skip to content

[Bug]: Port discovery keeps running lsof every 3 seconds while no client is in the foreground #29747

Open

Description

@onlydole

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. On macOS or Linux, open a terminal in any thread so the scan isn't skipped as having nothing to find (perf(server): skip idle port discovery on Linux and macOS #20975).
  2. Open a thread whose details panel shows its Servers section, or open an empty preview.
  3. Hide the window, switch to another app, or move the browser tab to the background. Leave it there.
  4. Watch the server's process activity or trace file. lsof -iTCP -sTCP:LISTEN -P -n -F pcn keeps running every 3 seconds, and PortDiscovery.pollTick spans keep arriving at the same rate.

Expected behavior

While no client is in the foreground, the server stops the 3-second port poll, the way other background work already checks BackgroundPolicy. VcsStatusBroadcaster and UsageLimitSources call shouldRunScopeWork, and the pull request sweep in ThreadPullRequestService calls shouldRunOpportunisticWork. When a client returns to the foreground, the server list catches up on the next tick.

Actual behavior

The poll loop in apps/server/src/preview/PortScanner.ts (pollIfRetained, repeated on Schedule.spaced(POLL_INTERVAL)) checks only retainCount > 0 and never consults BackgroundPolicy. The web and desktop clients hold subscribeDiscoveredLocalServers whenever the thread details panel shows its Servers section or the preview empty state is mounted. A hidden window or a background tab keeps the scan running for as long as it stays open.

Numbers from one real install, over a 112-minute trace window:

  • 2,483 lsof spawns, with a median of 101 ms each, for 243 s of total process time.
  • A flat 290 spawns per 15 minutes for the whole window. At that rate the poll runs about 28,800 times a day while the panel stays mounted.
  • The six PortDiscovery.* span names added about 5.5 MB of trace data.

Impact

Minor bug or occasional failure

Version or commit

main @ 5b9731c

Environment

macOS. Linux runs the same loop with lsof, or with the /proc scan when lsof is missing.

Possible fix

Skip the scheduled tick unless backgroundPolicy.shouldRunOpportunisticWork is true, the same check the pull request sweep uses. The initial scan on subscribe and the refresh after previewStopLocalServer would stay unconditional, so opening the panel or stopping a server still shows fresh results right away. The change is server-only. Web and desktop already report foreground leases, and mobile doesn't use this subscription.

A few behavior questions for a maintainer:

  • shouldRunOpportunisticWork also returns false while the host is locked, suspended, under thermal pressure, or in low power mode on the Balanced profile. The Balanced description already says it pauses probes in low power mode, but a focused user in Low Power Mode would stop seeing new servers until they leave it. Gating on activeForegroundLeaseCount > 0 from the policy snapshot would avoid that.
  • On Balanced, a window that is visible but unfocused, with no input for 45 seconds, doesn't hold a foreground lease. A server list watched on a second monitor would stop updating until the user interacts with it again.
  • The Performance profile promises scoped probes while any subscribed client stays connected. Port discovery has no background scope, so it would follow the foreground rule in every profile unless it gets a scope of its own, which needs client changes.

Related work

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions