feat(hooks): add on_stop and on_exit#291
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances Pitchfork's daemon lifecycle management by introducing Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces on_stop and on_exit lifecycle hooks, which is a great feature for resource cleanup and notifications. The implementation is well-tested and the documentation is updated thoroughly across all relevant files. I've found one area in the core lifecycle logic with significant code duplication that could be refactored to improve maintainability. See my specific comment for details.
Greptile SummaryThis PR adds two new lifecycle hooks — Key implementation decisions:
The only minor issue found is a documentation inaccuracy: the env-var table describes Confidence Score: 5/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Daemon process exits] --> B{is_stopping?}
B -- yes --> C[exit_reason = stop]
B -- no --> D{status.success?}
D -- yes --> E[exit_reason = exit]
D -- no --> F{hook_retry_count >= hook_retry?}
F -- yes --> G[exit_reason = fail]
F -- no --> H[No hooks fired\nDaemon marked Errored\ncheck_retry schedules restart]
H --> I[on_retry fires before next attempt]
C --> J[Fire on_stop + on_exit]
E --> K[Fire on_exit only]
G --> L[Fire on_fail + on_exit]
J --> M[Register JoinHandles in hook_tasks]
K --> M
L --> M
N[Supervisor shutdown / signal] --> O[close: stop each daemon]
O --> P[Wait active_monitors == 0\nup to 5s]
P --> Q[Drain hook_tasks\n30s per task]
Q --> R[exit 0]
Reviews (8): Last reviewed commit: "feat(hooks): add `on_stop` and `on_exit`" | Re-trigger Greptile |
846813f to
2a0ba14
Compare
2a0ba14 to
9df6d99
Compare
9df6d99 to
cad8bee
Compare
|
Great work @gaojunran, really appreciate the speed 🔥 |
|
Fuzzy Manual testing on this branch, it seems the hooks are indeed working correctly 🥳 Test 1: Explicit stop against a live process[daemons.test]
run = "sleep 10"
[daemons.test.hooks]
on_stop = "sh -c 'echo on_stop: $PITCHFORK_EXIT_REASON >> /tmp/pf.log'"
on_exit = "sh -c 'echo on_exit: $PITCHFORK_EXIT_REASON >> /tmp/pf.log'"Result: both Test 2: Natural process termination (no explicit stop)[daemons.test-race]
run = "sleep 0.5"
[daemons.test.hooks]
on_stop = "sh -c 'echo on_stop: $PITCHFORK_EXIT_REASON >> /tmp/pf.log'"
on_exit = "sh -c 'echo on_exit: $PITCHFORK_EXIT_REASON >> /tmp/pf.log'"
Loop of 20 runs — start daemon, wait 0.4s, attempt stop (daemon already gone), wait 0.5s for async hooks to settle, read log. for i in $(seq 1 20); do
rm -f /tmp/pf-race.log
pitchfork start test-race
sleep 0.4
pitchfork stop test-race
sleep 0.5
echo "Run $i: $(cat /tmp/pf-race.log 2>/dev/null | tr '\n' '|' || echo 'NO HOOKS')"
doneResult:
One note for documentation: hooks are fire-and-forget async, so reading their output immediately after pitchfork stop returns can produce false negatives. A short settle delay is needed in the test harnesses that check hook side effects. Worth a note in the lifecycle hooks guide so users don't assume hooks have completed when the CLI returns. Untested: the P1 race condition flagged by greptile (hooks dropping when stop() clears PID atomically before the monitoring task runs). The sub-second process lifetime approach Overall the happy path is rock solid!!!
🔥💚🔥 |
|
@aFuzzyBear thank you for your appreciation! there remains some CR comments and I will deal with them tomorrow. |
|
I cant say thank you enough 💚 |
cad8bee to
b6df629
Compare
b6df629 to
53ba506
Compare
53ba506 to
6d3b157
Compare
|
@jdx Ready for a review. It seems greptileai has no more comments and now it's more stable. |
## 🤖 New release * `pitchfork-cli`: 2.1.0 -> 2.2.0 <details><summary><i><b>Changelog</b></i></summary><p> <blockquote> ## [2.2.0](v2.1.0...v2.2.0) - 2026-03-24 ### Added - *(hooks)* add `on_stop` and `on_exit` ([#291](#291)) - impl `start --all-local` and `--all-global` ([#282](#282)) ### Other - *(deps)* lock file maintenance ([#292](#292)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: this PR only bumps the crate version and updates release notes; no runtime code changes are included. > > **Overview** > Bumps `pitchfork-cli` from `2.1.0` to `2.2.0` in `Cargo.toml`/`Cargo.lock` and adds the `2.2.0` entry to `CHANGELOG.md` (documenting new hooks, new `start --all-local/--all-global` flags, and dependency lockfile maintenance). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 07cb510. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
addresses #285.