fix: ensure there is always a free thread for non-worker scripts (#105)

This commit is contained in:
Kévin Dunglas 2022-11-14 22:45:51 +01:00 committed by GitHub
parent 6a6dda5ed9
commit 878a30d92f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 23 additions and 10 deletions

View File

@ -558,9 +558,8 @@ static void *manager_thread(void *arg) {
free(arg);
uintptr_t rh;
while ((rh = go_fetch_request())) {
while ((rh = go_fetch_request()))
thpool_add_work(thpool, go_execute_script, (void *) rh);
}
/* channel closed, shutdown gracefully */
thpool_wait(thpool);

View File

@ -5,8 +5,9 @@
// [FrankenPHP app server]: https://frankenphp.dev
package frankenphp
//go:generate rm -Rf C-Thread-Pool/
//go:generate git clone --branch=feat/mac-os-compat --depth=1 git@github.com:dunglas/C-Thread-Pool.git
//go:generate rm -rf C-Thread-Pool/.git C-Thread-Pool/.circleci C-Thread-Pool/docs C-Thread-Pool/tests
//go:generate rm -Rf C-Thread-Pool/.git C-Thread-Pool/.circleci C-Thread-Pool/docs C-Thread-Pool/tests
// #cgo CFLAGS: -Wall
// #cgo CFLAGS: -I/usr/local/include/php -I/usr/local/include/php/Zend -I/usr/local/include/php/TSRM -I/usr/local/include/php/main
@ -45,6 +46,7 @@ var (
AlreaydStartedError = errors.New("FrankenPHP is already started")
InvalidPHPVersionError = errors.New("FrankenPHP is only compatible with PHP 8.2+")
ZendSignalsError = errors.New("Zend Signals are enabled, recompile PHP with --disable-zend-signals")
NotEnoughThreads = errors.New("the number of threads must be superior to the number of workers")
MainThreadCreationError = errors.New("error creating the main thread")
RequestContextCreationError = errors.New("error during request context creation")
RequestStartupError = errors.New("error during PHP request startup")
@ -221,16 +223,18 @@ func Init(options ...Option) error {
opt.workers[i].num = numCPU
}
numWorkers += w.num
numWorkers += opt.workers[i].num
}
if opt.numThreads <= 0 {
if numWorkers >= numCPU {
// Keep a free thread to handle requests not handled by a worker
opt.numThreads = numCPU + 1
// Start at least as many threads as workers, and keep a free thread to handle requests in non-worker mode
opt.numThreads = numWorkers + 1
} else {
opt.numThreads = numCPU
}
} else if opt.numThreads <= numWorkers {
return NotEnoughThreads
}
switch C.frankenphp_check_version() {

View File

@ -39,9 +39,6 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), *
if opts == nil {
opts = &testOptions{}
}
if opts.nbWorkers == 0 {
opts.nbWorkers = 2
}
if opts.nbParrallelRequests == 0 {
opts.nbParrallelRequests = 100
}

2
testdata/Caddyfile vendored
View File

@ -1,7 +1,7 @@
{
debug
frankenphp {
#worker ./phpinfo.php
worker ./phpinfo.php
}
}

View File

@ -49,6 +49,19 @@ func TestWorkerDie(t *testing.T) {
}, &testOptions{workerScript: "die.php", nbWorkers: 1, nbParrallelRequests: 10})
}
func TestNonWorkerModeAlwaysWorks(t *testing.T) {
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", "http://example.com/index.php", nil)
w := httptest.NewRecorder()
handler(w, req)
resp := w.Result()
body, _ := io.ReadAll(resp.Body)
assert.Contains(t, string(body), "I am by birth a Genevese")
}, &testOptions{workerScript: "phpinfo.php"})
}
func ExampleServeHTTP_workers() {
if err := frankenphp.Init(
frankenphp.WithWorkers("worker1.php", 4),