* feat(prefork): add WatchMaster and callback support for child process management
* feat(prefork): add CommandProducer for customizable child process commands
* refactor(prefork): improve comments and parameter order in ListenAndServeTLS
* refactor(prefork): enhance logging message and clarify OnChildRecover callback comment
* fix(prefork): add Windows support to watchMaster
On Windows, os.Getppid() returns a static PID that doesn't change when
the parent exits (no reparenting). Use FindProcess+Wait instead, which
correctly detects parent exit. Also document why masterPID comparison
works for Docker containers (master PID 1 case).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(prefork): extract listenAsChild to eliminate DRY violation
The three ListenAndServe* methods had identical child setup code
(listen, set ln, watch master). Extract to listenAsChild() for
cleaner code. Also add comment for the magic file descriptor number 3.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(prefork): restore upstream ListenAndServeTLS parameter order
Keep upstream's (addr, certKey, certFile) signature to avoid breaking
callers. Fix the doc comment to match the actual parameter order instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(prefork): address lint errors and review feedback
Lint fixes:
- Remove unused Reuseport field write in test (govet/unusedwrite)
- Replace fmt.Errorf with errors.New for static errors (perfsprint)
Review feedback (Copilot):
- Validate CommandProducer returns a started command (nil/Process check)
- Clarify ListenAndServeTLS doc: parameter order and internal forwarding
- Use hermetic test binary re-exec instead of external 'go' binary
- Rename misleading test to reflect what it actually asserts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(prefork): address maintainer review feedback
- watchMaster: log errors from FindProcess/Wait instead of swallowing
- watchMaster: don't call OnMasterDeath if FindProcess fails
- OnChildRecover: change signature to func(pid int), drop unused error return
- OnChildSpawn: add comment clarifying deferred cleanup handles the child
- CommandProducer: improve docs describing contract and use cases
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(prefork): address erikdubbelboer review feedback
- OnChildRecover: signature changed to func(oldPid, newPid int) so
callers can track which process was replaced
- OnChildSpawn: also called for recovered children (a recovered child
is still a spawned child)
- watchMaster: call OnMasterDeath when FindProcess fails (process is
most likely gone)
- CommandProducer: document that FASTHTTP_PREFORK_CHILD=1 must be set
in the child env, and what the default does when nil
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(prefork): avoid zombie processes and replace shallow tests
- Move Wait() goroutine before OnChildSpawn so Kill()+Wait() works
correctly if a callback fails and the deferred cleanup runs
- Add Wait() call in deferred cleanup after Kill() to reap children
- Same fix in recovery loop
- Remove shallow callback tests that only tested Go compiler
- Add Test_Prefork_Lifecycle: runs full prefork with CommandProducer,
verifies callbacks fire in correct order with correct arguments
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(prefork): ensure recovery default stays positive
* test(prefork): isolate lifecycle tests
* fix(prefork): tighten recovery callback flow
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: detect master process death in prefork children
Prefork child processes had no mechanism to detect if the master process
died unexpectedly. Children would become orphans, get reparented to
PID 1, and keep running silently with no supervision.
Add a watchMaster goroutine that stores the original parent PID at
startup and exits when the parent PID changes, matching the approach
used in gofiber/fiber.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add integration test for watchMaster orphan detection
Verifies that prefork children exit when the master process is killed,
using a two-level subprocess chain (test → master → child) with pipe-based
synchronization to ensure the child has recorded its PPID before the
master is killed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: pass masterPID to watchMaster and clean up tests
Capture PPID before launching the goroutine to eliminate a race between
the PPID snapshot and the ready signal. Align test style with the rest
of the project (t.Parallel, naming, ASCII-only comments).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: make prefork orphan detection configurable via OnMasterDeath callback
Address review feedback: make watchMaster opt-in via an OnMasterDeath
callback field (nil/off by default for backwards compatibility). Users
can set DefaultOnMasterDeath for os.Exit(1) or provide custom cleanup.
Also fixes ticker leak in watchMaster.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* address review feedback: remove DefaultOnMasterDeath, delete tests, fix log message
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
It's better to use an environment variable as they are more standard.
They way flags are parsed isn't standardized within the Go ecosystem.
Fixes: https://github.com/valyala/fasthttp/issues/1782
* Run go test on github actions
travis-ci.org has stopped.
See also: https://github.com/curl/curl/issues/7150
Downside: github actions don't support ppc64le
* Run less
* delete .travis.yml
* Remove travis + minor lint fixes
* Make the prefork mode more robust
The main process will exit if one of the prefork child processes doesn't complete successfully under the current prefork mode, so it ought to make sure that all child processes run independently and the main process will only exit after all child processes are finished.
* Start over those failed child processes automatically
* Kill all child processes before main process exits
* Remove redundant code
* Add configurable threshold of starting over child processes
* Return a error of RecoverThreshold
* Resolved requested changes
* Add logs
* Resolve requested changes
* feat: workflow to valid security using GoSec
* Update security.yml
* Fix gosec problems
These are all either false positives or os.Open operations done on
filenames supplied by the fasthttp user which we have to assume is safe.
* Just ignore some rules globally
* Fix more warnings
* No more warnings
Co-authored-by: Erik Dubbelboer <erik@dubbelboer.com>