perf: use periodic log flushing instead of per-line#139
Merged
Conversation
Replace per-line log flushing with periodic flushing (every 1 second). This significantly reduces I/O overhead for chatty daemons while still ensuring logs are written to disk in a timely manner. - Remove flush() calls after each stdout/stderr line - Add periodic flush interval (1 second) - Add final flush when daemon exits Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| if let Err(e) = log_appender.flush().await { | ||
| error!("Failed to flush log for daemon {id}: {e}"); | ||
| } | ||
| } |
There was a problem hiding this comment.
Flush interval prevents fallback exit path from triggering
Low Severity
The unconditional log_flush_interval.tick() branch prevents the else => break fallback from ever executing. In tokio's select!, the else branch only fires when all other branches are disabled, but the flush interval is always active. This makes the fallback exit path at lines 768-776 (which handles "streams closed but process hasn't exited yet") unreachable. If the exit channel fails unexpectedly, the loop would run forever instead of breaking gracefully.
Additional Locations (1)
- Remove unreachable `else => break` from select! (log_flush_interval.tick() is always available, making else branch unreachable) - Reduce flush interval from 1s to 500ms for better responsiveness - Flush logs immediately before sending ready notifications so clients see logs right after `--wait-ready` returns - Add #[allow(unused_assignments)] for exit_status initialization The test_ready_http_check failure was caused by logs not being flushed before the ready notification was sent, so the client couldn't see the startup logs. The test_logs_tail_command failure was a race condition with the 1s flush interval. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Merged
jdx
added a commit
that referenced
this pull request
Jan 19, 2026
## 🤖 New release * `pitchfork-cli`: 0.3.0 -> 0.3.1 <details><summary><i><b>Changelog</b></i></summary><p> <blockquote> ## [0.3.1](v0.3.0...v0.3.1) - 2026-01-19 ### Added - implement daemon dependency resolution ([#135](#135)) - add restart command to CLI ([#134](#134)) ### Fixed - restart command preserves daemon dependency configuration ([#142](#142)) - add missing depends field to restart command ([#136](#136)) - set IPC socket permissions to 0600 for security ([#133](#133)) - handle shell command parsing errors instead of silently failing ([#132](#132)) ### Other - reduce unnecessary daemon cloning in loops ([#144](#144)) - use periodic log flushing instead of per-line ([#139](#139)) - refresh only tracked PIDs instead of all processes ([#141](#141)) - cache compiled regex patterns ([#143](#143)) ### Security - add rate limiting to IPC server ([#137](#137)) - canonicalize config paths to prevent symlink exploitation ([#138](#138)) - add centralized daemon ID validation ([#140](#140)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Prepares the 0.3.1 release and updates metadata/documentation accordingly. > > - **Changelog**: Adds `0.3.1` entry detailing added dependency resolution, new `restart` command, fixes, performance tweaks, and security hardening > - **Version bumps**: Updates `version` to `0.3.1` in `Cargo.toml`, `Cargo.lock`, `docs/cli/commands.json`, `docs/cli/index.md`, and `pitchfork.usage.kdl` > - **Docs regen**: Refreshes CLI docs/spec to reflect the new version (no behavioral changes in this diff) > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 9f9d386. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Merged
jdx
added a commit
that referenced
this pull request
Jan 19, 2026
## 🤖 New release * `pitchfork-cli`: 1.0.0 <details><summary><i><b>Changelog</b></i></summary><p> <blockquote> ## [1.0.0](https://github.com/jdx/pitchfork/releases/tag/v1.0.0) - 2026-01-19 ### Added - implement daemon dependency resolution ([#135](#135)) - add restart command to CLI ([#134](#134)) ### Fixed - restart command preserves daemon dependency configuration ([#142](#142)) - add missing depends field to restart command ([#136](#136)) - set IPC socket permissions to 0600 for security ([#133](#133)) - handle shell command parsing errors instead of silently failing ([#132](#132)) ### Other - bump version to 1.0.0 ([#147](#147)) - release v0.3.1 ([#121](#121)) - reduce unnecessary daemon cloning in loops ([#144](#144)) - use periodic log flushing instead of per-line ([#139](#139)) - refresh only tracked PIDs instead of all processes ([#141](#141)) - cache compiled regex patterns ([#143](#143)) ### Security - add rate limiting to IPC server ([#137](#137)) - canonicalize config paths to prevent symlink exploitation ([#138](#138)) - add centralized daemon ID validation ([#140](#140)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Prepares the 1.0.0 release and updates `CHANGELOG.md` with the finalized notes. > > - Adds `1.0.0` section: daemon dependency resolution, new CLI `restart` command, fixes for dependency preservation and shell parsing, secure IPC socket perms, plus performance/maintenance updates > - Documents security hardening: IPC rate limiting, config path canonicalization, centralized daemon ID validation > - Retains prior `0.3.1` notes for historical context > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 4182984. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Problem
The supervisor was flushing logs after every single line of stdout/stderr output. For chatty daemons that produce many log lines per second, this caused excessive I/O overhead and high CPU usage.
Solution
flush()calls after each line writeThis maintains log durability (logs are still written to disk every second) while dramatically reducing I/O operations for high-output daemons.
Test plan
cargo buildpasses🤖 Generated with Claude Code
Note
Reduces I/O by batching daemon log writes while preserving timely visibility at key events.
flush()after stdout/stderr writes; addtokio::time::interval(500ms)periodic flush in the select loopflush()before sending readiness notifications (output/HTTP/port/delay) and upon process exit; add a final flush after loop endsexit_rx.recv()for termination (remove unreachableelse => break); trackexit_statusfor final resultWritten by Cursor Bugbot for commit e48e5c7. This will update automatically on new commits. Configure here.