Compare commits

...

7 Commits

Author SHA1 Message Date
Dallin Romney
807d95dd3f Merge pull request #9568 from yumosx/fix-lsof
fix(resource-monitoring): fix lsof file descriptor leak
2026-01-31 15:33:39 -08:00
Dallin Romney
895632c0a5 fix: detect WSL remote for shell PATH resolution (#9934)
When Windows host connects to WSL remote, getEnvPathFromUserShell() was
returning undefined because it checked only process.platform === "win32".

Add remoteName parameter to getEnvPathFromUserShell() and use the
isWindowsHostWithWslRemote pattern (consistent with resolveCommandForPlatform)
to allow shell PATH detection for WSL remotes.

Fixes #9737

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 15:26:05 -08:00
shanevcantwell
939b44b39f fix: detect WSL remote for shell PATH resolution
When Windows host connects to WSL remote, getEnvPathFromUserShell() was
returning undefined because it checked only process.platform === "win32".

Add remoteName parameter to getEnvPathFromUserShell() and use the
isWindowsHostWithWslRemote pattern (consistent with resolveCommandForPlatform)
to allow shell PATH detection for WSL remotes.

Fixes #9737

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 18:51:11 -07:00
alanw
056622faa0 fix: simplify file descriptor count calculation 2026-01-19 01:46:26 +00:00
alanw
676e31d28e fix(ResourceMonitoringService): prevent negative file descriptor counts and remove test cases 2026-01-16 05:17:39 +00:00
alanw
df83e66d5c fix(ResourceMonitoringService): initialize fd check time and count on start 2026-01-16 04:20:46 +00:00
alanw
a99288f25a fix(resource-monitoring): prevent file descriptor count leak by adding caching 2026-01-16 03:27:48 +00:00
3 changed files with 42 additions and 16 deletions

View File

@@ -563,10 +563,15 @@ Org-level secrets can only be used for MCP by Background Agents (https://docs.co
// Set the initial PATH from process.env // Set the initial PATH from process.env
env.PATH = process.env.PATH; env.PATH = process.env.PATH;
// For non-Windows platforms, try to get the PATH from user shell // For non-Windows platforms or WSL remotes, try to get the PATH from user shell
if (process.platform !== "win32") { const ideInfo = await this.extras?.ide?.getIdeInfo();
const isWindowsHostWithWslRemote =
process.platform === "win32" && ideInfo?.remoteName === "wsl";
if (process.platform !== "win32" || isWindowsHostWithWslRemote) {
try { try {
const shellEnvPath = await getEnvPathFromUserShell(); const shellEnvPath = await getEnvPathFromUserShell(
ideInfo?.remoteName,
);
if (shellEnvPath && shellEnvPath !== process.env.PATH) { if (shellEnvPath && shellEnvPath !== process.env.PATH) {
env.PATH = shellEnvPath; env.PATH = shellEnvPath;
} }

View File

@@ -2,9 +2,12 @@ import { exec } from "child_process";
import { promisify } from "util"; import { promisify } from "util";
const execAsync = promisify(exec); const execAsync = promisify(exec);
export async function getEnvPathFromUserShell(): Promise<string | undefined> { export async function getEnvPathFromUserShell(
if (process.platform === "win32") { remoteName?: string,
console.warn(`${getEnvPathFromUserShell.name} not implemented for Windows`); ): Promise<string | undefined> {
const isWindowsHostWithWslRemote =
process.platform === "win32" && remoteName === "wsl";
if (process.platform === "win32" && !isWindowsHostWithWslRemote) {
return undefined; return undefined;
} }

View File

@@ -45,6 +45,9 @@ class ResourceMonitoringService {
private maxHistorySize = 300; // Keep 5 minutes at 1s intervals private maxHistorySize = 300; // Keep 5 minutes at 1s intervals
private lastCpuUsage = process.cpuUsage(); private lastCpuUsage = process.cpuUsage();
private lastTimestamp = Date.now(); private lastTimestamp = Date.now();
private lastFdCheckTime = Date.now();
private fdCheckIntervalMs = 5000; // Check file descriptors every 5 seconds
private cacheFileCount: number | null = null;
async initialize(): Promise<void> { async initialize(): Promise<void> {
// Start monitoring if verbose mode is enabled // Start monitoring if verbose mode is enabled
@@ -70,6 +73,12 @@ class ResourceMonitoringService {
this.lastCpuUsage = process.cpuUsage(); this.lastCpuUsage = process.cpuUsage();
this.lastTimestamp = Date.now(); this.lastTimestamp = Date.now();
// Initialize file descriptor count on start
this.updateFileDescriptorCount().catch(() => {
// Ignore errors during initialization
});
this.lastFdCheckTime = Date.now();
this.monitoringInterval = setInterval(() => { this.monitoringInterval = setInterval(() => {
this.collectResourceUsage(); this.collectResourceUsage();
}, this.intervalMs); }, this.intervalMs);
@@ -127,16 +136,10 @@ class ResourceMonitoringService {
}, },
}; };
// Try to get file descriptor count (Unix only) // Use cached file descriptor count to avoid lsof command leak
this.getFileDescriptorCount() if (this.cacheFileCount !== null) {
.then((count) => { usage.fileDescriptors = this.cacheFileCount;
if (count !== null) { }
usage.fileDescriptors = count;
}
})
.catch(() => {
// Ignore errors for file descriptor counting
});
return usage; return usage;
} }
@@ -215,6 +218,14 @@ class ResourceMonitoringService {
this.resourceHistory = this.resourceHistory.slice(-this.maxHistorySize); this.resourceHistory = this.resourceHistory.slice(-this.maxHistorySize);
} }
// Periodically update file descriptor count to prevent lsof command leak
// Issue: https://github.com/continuedev/continue/issues/9422
const now = Date.now();
if (now - this.lastFdCheckTime >= this.fdCheckIntervalMs) {
this.updateFileDescriptorCount();
this.lastFdCheckTime = now;
}
// Check for potential issues and log warnings // Check for potential issues and log warnings
this.checkResourceThresholds(usage); this.checkResourceThresholds(usage);
} catch (error) { } catch (error) {
@@ -251,6 +262,13 @@ class ResourceMonitoringService {
} }
} }
private async updateFileDescriptorCount(): Promise<void> {
const count = await this.getFileDescriptorCount();
if (count !== null) {
this.cacheFileCount = count;
}
}
private async getFileDescriptorCount(): Promise<number | null> { private async getFileDescriptorCount(): Promise<number | null> {
if (process.platform === "win32") { if (process.platform === "win32") {
return null; // Not supported on Windows return null; // Not supported on Windows