Daemon leaks on Linux: `stat -f` is macOS-only + missing PID-file guard
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 55/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Ít trao đổi
- Công nghệ
- bash, bun, typescript
Hướng nghiên cứu
Bắt đầu với bin/macrodata-hook.sh, đặc biệt là store_lastmod, check_files_changed, is_daemon_running và start_daemon; so sánh hành vi của chúng với macrodata-daemon.ts trên Linux. Chạy hook trong môi trường Linux và xác minh rằng các kiểm tra mtime hoạt động, đồng thời các lần gọi hook lặp lại không tạo ra các tiến trình daemon trùng lặp, kể cả khi tệp PID không tồn tại hoặc đã cũ.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
On Linux (e.g. WSL2 / Ubuntu), bin/macrodata-hook.sh has two bugs that compound into a daemon leak: every session-start or prompt-submit hook call can spawn a fresh macrodata-daemon.ts that never exits. On a machine that was left running for ~26 days with scheduled dreamtime + morning-prep sessions firing nightly, I ended up with 9 concurrent daemons holding ~14% RSS each, OOM-thrashing and pinning CPU.
Bug 1 — stat -f %m is BSD/macOS syntax
bin/macrodata-hook.sh uses stat -f %m in store_lastmod and check_files_changed. On GNU coreutils (Linux) -f means display filesystem status, not format. The call errors out:
$ stat -f %m ~/some/file
stat: cannot read file system information for '%m': No such file or directory
File: "/home/..."
Because the error is swallowed by 2>/dev/null, the command substitution returns the empty string. check_files_changed then compares "" against whatever is in .lastmod, always sees a mismatch, and reports "files changed" every prompt. This triggers signal_daemon_reload + re-injects static context on every hook fire.
GNU coreutils uses stat -c %Y. BSD/macOS coreutils uses stat -f %m. A portable helper handles both.
Bug 2 — No guard against duplicate daemon spawning when PID file is missing
is_daemon_running() only returns true when $PIDFILE exists and its PID is live. On my machine ~/.config/macrodata/.daemon.pid doesn't exist (possibly never written by the daemon, or removed, or the daemon is running with a different MACRODATA_ROOT). So is_daemon_running always returns false, and every start_daemon call spawns a new nohup bun run macrodata-daemon.ts & — which gets adopted by init when the parent shell dies and keeps running forever via the croner schedulers.
Over 26 days of scheduled sessions, this accumulated to 9 orphaned daemons:
PID ETIME %CPU %MEM CMD
317154 1-04:32:16 3.6 0.3 bun run .../macrodata-daemon.ts
317155 1-04:32:16 3.5 0.3 bun run .../macrodata-daemon.ts
317157 1-04:32:16 3.3 0.3 bun run .../macrodata-daemon.ts
373463 19:31:45 4.6 0.6 bun run .../macrodata-daemon.ts
435928 11:28:12 5.1 12.6 bun run .../macrodata-daemon.ts
453484 52:06 14.6 12.6 bun run .../macrodata-daemon.ts
453533 52:06 14.2 10.6 bun run .../macrodata-daemon.ts
462810 01:47 128 14.0 bun run .../macrodata-daemon.ts
463478 00:13 12.9 2.9 bun run .../macrodata-daemon.ts
Memory was 5.5/7.6 GiB used, 1.7/2 GiB swap used, 15-min load average 252.
Environment
- Linux 6.6.87.2-microsoft-standard-WSL2 (Ubuntu on WSL2)
- macrodata 0.2.1 (Claude Code plugin cache)
- bash, GNU coreutils
Suggested fix
Patch applied locally to bin/macrodata-hook.sh:
-
Portable mtime helper — try GNU
stat -c %Yfirst, fall back to BSDstat -f %m:get_mtime() { stat -c %Y "$1" 2>/dev/null || stat -f %m "$1" 2>/dev/null || echo 0 }Replace all
stat -f %m "$X" 2>/dev/null || echo 0call sites withget_mtime "$X". -
pgrep fallback in
is_daemon_running— if PID file is missing/stale, check whether any live daemon exists for this user before spawning:is_daemon_running() { if [ -f "$PIDFILE" ]; then local pid=$(cat "$PIDFILE") if kill -0 "$pid" 2>/dev/null; then return 0 fi fi if pgrep -u "$(id -u)" -f "macrodata-daemon\.ts" >/dev/null 2>&1; then return 0 fi return 1 }
Happy to open a PR if you'd like — wanted to file the report first in case you'd prefer a different shape (e.g. having the daemon write the PID file more defensively on startup, or adding flock around start_daemon).
- Ngôn ngữ chính
- TypeScript
- Star
- 119
- Fork
- 6
- Merge trung bình
- 1 giờ 32 phút
- Pull request đã merge (30 ngày)
- 2
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của ascorbic/macrodata
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 70/100
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 74/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
-
Support Cursor Đang mở
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 25/100
Tất cả issue của ascorbic/macrodata
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
Eynzof/Hermes-CN-Desktop#610 ·
-
[Bug]: Matrix progress drafts fail with "Matrix runtime not initialized" during tool activity Đang mởbug clawsweeper:linked-pr-open clawsweeper:needs-live-repro clawsweeper:no-new-fix-pr impact:message-loss issue-rating: 🐚 platinum hermit P2 regression
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
-
Client support matrix inclusion Đang mởenhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
calcite-components needs triage refactor
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
Esri/calcite-design-system#15203 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 90/100
danielmiessler/LifeOS#2218 ·