@askjo/camofox-browser 1.9.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +1 -0
- package/lib/reporter.js +47 -2
- package/openclaw.plugin.json +2 -2
- package/package.json +1 -1
- package/server.js +7 -5
package/Dockerfile
CHANGED
package/lib/reporter.js
CHANGED
|
@@ -593,6 +593,20 @@ function formatIssueBody(type, detail) {
|
|
|
593
593
|
}
|
|
594
594
|
|
|
595
595
|
// Context (misc extra data)
|
|
596
|
+
if (detail.nativeMemory) {
|
|
597
|
+
const nm = detail.nativeMemory;
|
|
598
|
+
sections.push('', '## Native Memory Details');
|
|
599
|
+
sections.push(`- **baseline:** ${nm.baselineMb} MB`);
|
|
600
|
+
sections.push(`- **current:** ${nm.currentMb} MB`);
|
|
601
|
+
sections.push(`- **high-water:** ${nm.highWaterMb} MB`);
|
|
602
|
+
sections.push(`- **growth:** ${nm.growthMb} MB`);
|
|
603
|
+
sections.push(`- **node RSS:** ${nm.rssMb} MB`);
|
|
604
|
+
sections.push(`- **heap used:** ${nm.heapUsedMb} MB`);
|
|
605
|
+
sections.push(`- **external:** ${nm.externalMb} MB`);
|
|
606
|
+
if (nm.lastSeenBrowserRssMb != null) sections.push(`- **browser RSS (last seen):** ${nm.lastSeenBrowserRssMb} MB`);
|
|
607
|
+
else sections.push(`- **browser RSS (last seen):** not captured (browser already dead)`);
|
|
608
|
+
}
|
|
609
|
+
|
|
596
610
|
if (detail.context && Object.keys(detail.context).length > 0) {
|
|
597
611
|
sections.push('', '<details><summary>Context</summary>', '', '```json', anonymize(JSON.stringify(detail.context, null, 2)), '```', '', '</details>');
|
|
598
612
|
}
|
|
@@ -806,22 +820,26 @@ export function createReporter(config) {
|
|
|
806
820
|
|
|
807
821
|
// --- Native memory leak tracking ---
|
|
808
822
|
// Track RSS minus JS heap over time to detect native/external memory leaks.
|
|
809
|
-
// Sample every 30s, alert if native memory stays >
|
|
823
|
+
// Sample every 30s, alert if native memory stays >400MB above baseline for
|
|
810
824
|
// 3 consecutive checks (~90s). This avoids false positives from:
|
|
811
825
|
// - Browser initialization spikes (first 2 min)
|
|
812
826
|
// - One-time allocations that stabilize
|
|
813
827
|
// - Post-session RSS that hasn't been reclaimed by the OS yet
|
|
828
|
+
// - Self-healing restart (kills browser at 200MB growth when sessions=0)
|
|
829
|
+
// The memory pressure restart in server.js fires at 200MB when idle.
|
|
830
|
+
// We only report at 400MB to catch cases where self-healing FAILED.
|
|
814
831
|
let nativeMemBaseline = null; // RSS - heapUsed at first measurement
|
|
815
832
|
let nativeMemHighWater = 0;
|
|
816
833
|
let lastNativeMemCheck = 0;
|
|
817
834
|
const NATIVE_MEM_CHECK_INTERVAL_MS = 30_000;
|
|
818
|
-
const NATIVE_MEM_LEAK_THRESHOLD_MB =
|
|
835
|
+
const NATIVE_MEM_LEAK_THRESHOLD_MB = 400; // alert only when growth exceeds self-healing threshold
|
|
819
836
|
const NATIVE_MEM_MIN_UPTIME_S = 120; // don't measure until process has been up 2 min
|
|
820
837
|
const NATIVE_MEM_CONSECUTIVE_REQUIRED = 3; // require 3 consecutive checks above threshold
|
|
821
838
|
const NATIVE_MEM_GRACE_CHECKS = 2; // skip 2 checks after baseline reset (let memory settle)
|
|
822
839
|
let nativeMemAlertFired = false;
|
|
823
840
|
let nativeMemConsecutiveAbove = 0; // consecutive checks above threshold
|
|
824
841
|
let nativeMemGraceRemaining = 0; // checks to skip after baseline reset
|
|
842
|
+
let lastSeenBrowserRssMb = null; // captured during growth checks while browser is alive
|
|
825
843
|
|
|
826
844
|
// SIGCONT detection -- macOS sends SIGCONT on wake from sleep/suspend
|
|
827
845
|
let lastSigcont = 0;
|
|
@@ -896,6 +914,20 @@ export function createReporter(config) {
|
|
|
896
914
|
// Require sustained growth -- one-time spikes aren't leaks.
|
|
897
915
|
// Must exceed threshold on 3 consecutive checks (~90s).
|
|
898
916
|
nativeMemConsecutiveAbove++;
|
|
917
|
+
|
|
918
|
+
// Capture browser RSS NOW while it may still be alive.
|
|
919
|
+
// By report time the browser is often killed by memory pressure restart,
|
|
920
|
+
// making browserRssMb null. This preserves the last-seen value.
|
|
921
|
+
try {
|
|
922
|
+
if (getContext) {
|
|
923
|
+
const ctx = getContext();
|
|
924
|
+
if (ctx.resourceOpts?.browserPid) {
|
|
925
|
+
const snap = collectResourceSnapshot(ctx.resourceOpts);
|
|
926
|
+
if (snap.browserRssMb != null) lastSeenBrowserRssMb = snap.browserRssMb;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
} catch { /* swallow */ }
|
|
930
|
+
|
|
899
931
|
if (nativeMemConsecutiveAbove >= NATIVE_MEM_CONSECUTIVE_REQUIRED) {
|
|
900
932
|
nativeMemAlertFired = true;
|
|
901
933
|
let extra = {};
|
|
@@ -903,6 +935,18 @@ export function createReporter(config) {
|
|
|
903
935
|
const resources = collectResourceSnapshot(extra.resourceOpts || {});
|
|
904
936
|
delete extra.resourceOpts;
|
|
905
937
|
|
|
938
|
+
// Skip report if sessions=0 — memory pressure restart handles idle leaks.
|
|
939
|
+
// Only report when sessions are active (restart CAN'T fire) or restart failed.
|
|
940
|
+
const sessionCount = resources.browserContexts ?? 0;
|
|
941
|
+
if (sessionCount === 0 && resources.browserRssMb == null) {
|
|
942
|
+
// Browser already dead, restart mechanism handled it. Don't spam.
|
|
943
|
+
// But if growth is extreme (>600MB), report anyway — restart may have failed.
|
|
944
|
+
if (growth < 600) {
|
|
945
|
+
// Self-healing. Skip report.
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
906
950
|
fileReport('leak:native-memory', ['auto-report', 'memory-leak'], {
|
|
907
951
|
message: `Native memory grew by ${growth}MB (baseline: ${nativeMemBaseline}MB, current: ${nativeMemMb}MB, high-water: ${nativeMemHighWater}MB)`,
|
|
908
952
|
uptimeMinutes: Math.round(process.uptime() / 60),
|
|
@@ -915,6 +959,7 @@ export function createReporter(config) {
|
|
|
915
959
|
rssMb: Math.round(mem.rss / 1048576),
|
|
916
960
|
heapUsedMb: Math.round(mem.heapUsed / 1048576),
|
|
917
961
|
externalMb: Math.round(mem.external / 1048576),
|
|
962
|
+
lastSeenBrowserRssMb,
|
|
918
963
|
},
|
|
919
964
|
context: extra,
|
|
920
965
|
});
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"id": "camofox-browser",
|
|
2
|
+
"id": "@skyfallsin/camofox-browser",
|
|
3
3
|
"name": "Camofox Browser",
|
|
4
4
|
"description": "Anti-detection browser automation for AI agents using Camoufox (Firefox-based)",
|
|
5
|
-
"version": "1.9.
|
|
5
|
+
"version": "1.9.1",
|
|
6
6
|
"envVars": {
|
|
7
7
|
"CAMOFOX_API_KEY": {
|
|
8
8
|
"description": "Secret key for the cookie-import endpoint. Cookie import is disabled when unset. Only set this if you need to import browser cookies and the server is local or access-controlled.",
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -4494,11 +4494,13 @@ setInterval(() => {
|
|
|
4494
4494
|
if (reaped > 0) log('warn', 'orphan page reaper closed leaked pages', { reaped });
|
|
4495
4495
|
}, 60_000);
|
|
4496
4496
|
|
|
4497
|
-
// Native memory pressure restart -- when all sessions are gone and
|
|
4498
|
-
// native memory has grown beyond threshold, kill
|
|
4499
|
-
// of waiting for the idle timer.
|
|
4500
|
-
//
|
|
4501
|
-
//
|
|
4497
|
+
// Native memory pressure restart -- when all sessions are gone and the Node
|
|
4498
|
+
// process's native memory (RSS minus V8 heap) has grown beyond threshold, kill
|
|
4499
|
+
// the browser process immediately instead of waiting for the idle timer.
|
|
4500
|
+
// Note: This measures Node/Playwright internal state (CDP buffers, glibc arenas),
|
|
4501
|
+
// NOT Firefox's own memory (which is a separate child process). Firefox jemalloc
|
|
4502
|
+
// fragmentation is tracked separately via browser RSS in /proc/<pid>/status.
|
|
4503
|
+
// The restart reclaims Playwright state; Firefox's process dies with it.
|
|
4502
4504
|
setInterval(() => {
|
|
4503
4505
|
if (sessions.size > 0 || !browser) return;
|
|
4504
4506
|
const mem = process.memoryUsage();
|