Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
214 commits
Select commit Hold shift + click to select a range
fe1158f
Decouple workers.
AlliBalliBaba Nov 1, 2024
ad34140
Moves code to separate file.
AlliBalliBaba Nov 1, 2024
89b211d
Cleans up the exponential backoff.
AlliBalliBaba Nov 2, 2024
7d2ab8c
Initial working implementation.
AlliBalliBaba Nov 2, 2024
f7e7d41
Refactors php threads to take callbacks.
AlliBalliBaba Nov 2, 2024
c03c59b
Cleanup.
AlliBalliBaba Nov 2, 2024
a9857dc
Cleanup.
AlliBalliBaba Nov 2, 2024
bac9555
Cleanup.
AlliBalliBaba Nov 2, 2024
a2f8d59
Cleanup.
AlliBalliBaba Nov 2, 2024
279924c
Merge branch 'main' into refactor/start-worker-threads-directly
AlliBalliBaba Nov 3, 2024
0825453
Adjusts watcher logic.
AlliBalliBaba Nov 3, 2024
17d5cbe
Adjusts the watcher logic.
AlliBalliBaba Nov 3, 2024
09e0ca6
Fix opcache_reset race condition.
AlliBalliBaba Nov 4, 2024
a726a2c
Merge branch 'main' into refactor/start-worker-threads-directly
AlliBalliBaba Nov 4, 2024
7f13ada
Fixing merge conflicts and formatting.
AlliBalliBaba Nov 4, 2024
13fb4bb
Prevents overlapping of TSRM reservation and script execution.
AlliBalliBaba Nov 5, 2024
a8a00c8
Adjustments as suggested by @dunglas.
AlliBalliBaba Nov 5, 2024
b4dd138
Adds error assertions.
AlliBalliBaba Nov 5, 2024
03f98fa
Adds comments.
AlliBalliBaba Nov 5, 2024
e52dd0f
Removes logs and explicitly compares to C.false.
AlliBalliBaba Nov 5, 2024
cd98e33
Resets check.
AlliBalliBaba Nov 5, 2024
4e2a2c6
Adds cast for safety.
AlliBalliBaba Nov 5, 2024
c51eb93
Fixes waitgroup overflow.
AlliBalliBaba Nov 5, 2024
89d8e26
Resolves waitgroup race condition on startup.
AlliBalliBaba Nov 6, 2024
3587243
Moves worker request logic to worker.go.
AlliBalliBaba Nov 7, 2024
ec32f0c
Removes defer.
AlliBalliBaba Nov 7, 2024
4e35698
Removes call from go to c.
AlliBalliBaba Nov 11, 2024
740fac7
Merge branch 'main' into refactor/start-worker-threads-directly
AlliBalliBaba Nov 15, 2024
8a272cb
Fixes merge conflict.
AlliBalliBaba Nov 15, 2024
ecce5d5
Adds fibers test back in.
AlliBalliBaba Nov 15, 2024
06ebd67
Refactors new thread loop approach.
AlliBalliBaba Nov 15, 2024
c811f4a
Removes redundant check.
AlliBalliBaba Nov 16, 2024
6bd047a
Adds compareAndSwap.
AlliBalliBaba Nov 16, 2024
55ad8ba
Refactor: removes global waitgroups and uses a 'thread state' abstrac…
AlliBalliBaba Nov 17, 2024
3ffbe06
Merge branch 'main' into refactor/start-worker-threads-directly
AlliBalliBaba Nov 17, 2024
01ed92b
Removes unnecessary method.
AlliBalliBaba Nov 17, 2024
790cccc
Updates comment.
AlliBalliBaba Nov 17, 2024
0dd2605
Removes unnecessary booleans.
AlliBalliBaba Nov 18, 2024
60a66b4
test
AlliBalliBaba Nov 24, 2024
4719fa8
First state machine steps.
AlliBalliBaba Nov 25, 2024
f72e8cb
Splits threads.
AlliBalliBaba Dec 6, 2024
d20e706
Minimal working implementation with broken tests.
AlliBalliBaba Dec 6, 2024
6747d15
Fixes tests.
AlliBalliBaba Dec 6, 2024
54dc267
Refactoring.
AlliBalliBaba Dec 7, 2024
660efcd
Merge branch 'main' into refactor/start-worker-threads-directly
AlliBalliBaba Dec 7, 2024
6214754
Fixes merge conflicts.
AlliBalliBaba Dec 7, 2024
00eb834
Formatting
AlliBalliBaba Dec 7, 2024
02b73b1
C formatting.
AlliBalliBaba Dec 7, 2024
421904e
More cleanup.
AlliBalliBaba Dec 7, 2024
cca2a00
Allows for clean state transitions.
AlliBalliBaba Dec 7, 2024
ec8aeb7
Adds state tests.
AlliBalliBaba Dec 7, 2024
b598bd3
Adds support for thread transitioning.
AlliBalliBaba Dec 7, 2024
66cedbd
Fixes the testdata path.
AlliBalliBaba Dec 7, 2024
06af5d5
Formatting.
AlliBalliBaba Dec 7, 2024
71c16bc
Allows transitioning back to inactive state.
AlliBalliBaba Dec 7, 2024
5095342
Fixes go linting.
AlliBalliBaba Dec 7, 2024
4b18059
Formatting.
AlliBalliBaba Dec 7, 2024
15429d9
Removes duplication.
AlliBalliBaba Dec 7, 2024
c080608
Applies suggestions by @dunglas
AlliBalliBaba Dec 7, 2024
a166b87
Removes redundant check.
AlliBalliBaba Dec 7, 2024
9491e6b
Locks the handler on restart.
AlliBalliBaba Dec 7, 2024
e795c86
Removes unnecessary log.
AlliBalliBaba Dec 8, 2024
68fa124
Adds frankenphp admin api.
AlliBalliBaba Dec 8, 2024
b6cbfae
Allows booting threads at runtime.
AlliBalliBaba Dec 8, 2024
f185279
Adds proper admin status codes and tests.
AlliBalliBaba Dec 8, 2024
ea0a4fe
Makes config smaller.
AlliBalliBaba Dec 8, 2024
fcb5f8c
Adds max threads option and debug status.
AlliBalliBaba Dec 8, 2024
a43ecbe
Adds test with debug message.
AlliBalliBaba Dec 8, 2024
b117bff
Formatting and comments.
AlliBalliBaba Dec 8, 2024
ef1bd0d
Changes Unpin() logic as suggested by @withinboredom
AlliBalliBaba Dec 9, 2024
8cd9061
Allows scaling regular threads.
AlliBalliBaba Dec 9, 2024
9e8d8f0
Only allows POST requests.
AlliBalliBaba Dec 9, 2024
a8a4545
Adds suggestions by @dunglas and resolves TODO.
AlliBalliBaba Dec 10, 2024
23a6362
Makes restarts fully safe.
AlliBalliBaba Dec 10, 2024
62224bf
Merge branch 'refactor/start-worker-threads-directly' into feat/worke…
AlliBalliBaba Dec 10, 2024
18e3e58
Will make the initial startup fail even if the watcher is enabled (as…
AlliBalliBaba Dec 10, 2024
3672c60
Also adds compareAndSwap to the test.
AlliBalliBaba Dec 10, 2024
38f87b7
Adds comment.
AlliBalliBaba Dec 10, 2024
96265d3
Merge branch 'refactor/start-worker-threads-directly' into feat/worke…
AlliBalliBaba Dec 10, 2024
d97ebfe
Prevents panic on initial watcher startup.
AlliBalliBaba Dec 10, 2024
950a509
Merge branch 'refactor/start-worker-threads-directly' into feat/worke…
AlliBalliBaba Dec 11, 2024
5f1ec1f
Cleans up admin endpoints.
AlliBalliBaba Dec 11, 2024
7c61dfa
Fixes admin test.
AlliBalliBaba Dec 11, 2024
2af993e
Boots a thread in a test.
AlliBalliBaba Dec 11, 2024
547139f
Sets more explicit max_threads.
AlliBalliBaba Dec 11, 2024
c8bf1ec
Adjusts naming.
AlliBalliBaba Dec 12, 2024
7f2b94e
Adds docs.
AlliBalliBaba Dec 12, 2024
df78254
Changes logic to actually terminate the thread.
AlliBalliBaba Dec 12, 2024
ec0bc0f
Removes the test's randomness.
AlliBalliBaba Dec 13, 2024
8f10407
Adds comments.
AlliBalliBaba Dec 13, 2024
91c324d
Adds comments.
AlliBalliBaba Dec 13, 2024
ff06bd7
Scaling v1.
AlliBalliBaba Dec 15, 2024
50ba106
Scaling v2.
AlliBalliBaba Dec 15, 2024
bfe3de1
Allows regular thread scaling.
AlliBalliBaba Dec 15, 2024
e9f62b9
Refactors wait-time.
AlliBalliBaba Dec 15, 2024
21949dd
Explicitly requires setting max_threads.
AlliBalliBaba Dec 15, 2024
39a7fc9
Removes redundant check.
AlliBalliBaba Dec 15, 2024
442a558
Removes unnecessary import.
AlliBalliBaba Dec 15, 2024
c213fc9
Records clock time.
AlliBalliBaba Dec 17, 2024
58daaa5
Saves CPU metrics of last 100 requests.
AlliBalliBaba Dec 17, 2024
14925f6
Integrates CPU tracking.
AlliBalliBaba Dec 18, 2024
d408bdd
Replaces clock with probing.
AlliBalliBaba Dec 19, 2024
8fc3293
fmt.
AlliBalliBaba Dec 19, 2024
0314247
Adds autoscale tests.
AlliBalliBaba Dec 19, 2024
bd4af11
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Dec 19, 2024
dc10546
Merges main.
AlliBalliBaba Dec 19, 2024
3b9f577
Fixes alpine (probably)
AlliBalliBaba Dec 19, 2024
790ce4e
Fixes alpine (definitely)
AlliBalliBaba Dec 19, 2024
29de62a
go fmt
AlliBalliBaba Dec 19, 2024
b447412
Removes unnecessary 'isProtected'
AlliBalliBaba Dec 19, 2024
6fa90d6
Adds perf tests.
AlliBalliBaba Dec 20, 2024
3bd7c76
Adds request status message to thread debug status.
AlliBalliBaba Dec 21, 2024
45cd915
Adjusts performance tests.
AlliBalliBaba Dec 21, 2024
af40470
Adds an exponential backoff on request overflow.
AlliBalliBaba Dec 21, 2024
d5e8f86
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Dec 21, 2024
c7acb25
changes dir.
AlliBalliBaba Dec 21, 2024
8c22cbf
Linting and formatting.
AlliBalliBaba Dec 22, 2024
745b29b
Linting and formatting.
AlliBalliBaba Dec 22, 2024
68ae2e4
Adds explicit scaling tests.
AlliBalliBaba Dec 22, 2024
09a5caf
Adjusts perf tests.
AlliBalliBaba Dec 22, 2024
3cfcb11
Uses different worker in removal test.
AlliBalliBaba Dec 22, 2024
cbe45fc
More formatting fixes.
AlliBalliBaba Dec 22, 2024
1d8e973
Replaces inline errors and adjusts comments.
AlliBalliBaba Dec 22, 2024
bf48b14
Formatting.
AlliBalliBaba Dec 22, 2024
4f0cc8a
Formatting.
AlliBalliBaba Dec 22, 2024
d483baf
Formatting.
AlliBalliBaba Dec 22, 2024
d222520
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Dec 22, 2024
4807947
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Dec 23, 2024
eef7815
Implements suggestions by @dunglas.
AlliBalliBaba Dec 25, 2024
601a43a
Adds note.
AlliBalliBaba Dec 26, 2024
971e1dc
Formatting.
AlliBalliBaba Dec 26, 2024
f4f9576
suggestion: Refactor scaling strategy (#1289)
withinboredom Dec 29, 2024
6ec9ad9
Merge branch 'feat/auto-scale-clock-time' of https://github.com/dungl…
AlliBalliBaba Dec 29, 2024
5282e32
Resets strategy and fixes tests.
AlliBalliBaba Dec 29, 2024
83d8c11
Adds scaling strategies.
AlliBalliBaba Dec 29, 2024
c094680
Fixes test reloading.
AlliBalliBaba Dec 29, 2024
3ba080a
Prevents threads from respawning after shutdown.
AlliBalliBaba Dec 30, 2024
7934b50
Adjusts transition tests.
AlliBalliBaba Dec 30, 2024
eb5e76d
Simplifies scaling.
AlliBalliBaba Jan 9, 2025
f33aaad
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Jan 9, 2025
5f70afb
Shows the original request path in debug status.
AlliBalliBaba Jan 9, 2025
9dcc2cd
Adds automatic thread limit calculation.
AlliBalliBaba Jan 10, 2025
ed90b75
Properly forwards automatic max threads.
AlliBalliBaba Jan 10, 2025
d047149
Adds ini overrides.
AlliBalliBaba Jan 10, 2025
5bdd50c
Adds Caddy php ini directive (for testing)
AlliBalliBaba Jan 10, 2025
936556b
Adds explicit nil check
AlliBalliBaba Jan 10, 2025
6758903
Adds php.ini override test.
AlliBalliBaba Jan 10, 2025
548d095
Fixes linting and conversions.
AlliBalliBaba Jan 10, 2025
2761d9c
Fixes fuzzing tests.
AlliBalliBaba Jan 10, 2025
36d3f54
clang-format
AlliBalliBaba Jan 10, 2025
cd5c905
Checks for original request existence on debug status.
AlliBalliBaba Jan 10, 2025
98f2279
Changes the memory calculation implementation
AlliBalliBaba Jan 10, 2025
a16de66
Renames var.
AlliBalliBaba Jan 10, 2025
6a6d040
Reduces the stall-time.
AlliBalliBaba Jan 10, 2025
83e0c08
Adjusts scaling logic and comments.
AlliBalliBaba Jan 10, 2025
79447b8
Swaps to unix sys package.
AlliBalliBaba Jan 10, 2025
0545e1b
Only supports CPU probing on unix and SysMemory on Linux.
AlliBalliBaba Jan 11, 2025
615662e
Adjusts timers and passes the main thread directly to scaling.
AlliBalliBaba Jan 11, 2025
618345b
Properly overrides ini settings on startup.
AlliBalliBaba Jan 12, 2025
a8b2c7c
clang-format
AlliBalliBaba Jan 12, 2025
9e4a9ca
Adds php_ini error.
AlliBalliBaba Jan 12, 2025
ca20704
Adds ini config.
AlliBalliBaba Jan 12, 2025
3e20e8f
Moves ini overrides to #else.
AlliBalliBaba Jan 15, 2025
7ce4c09
Adds some max_threads docs.
AlliBalliBaba Jan 15, 2025
2b1427b
Shows special debug message if in-between worker requests.
AlliBalliBaba Jan 15, 2025
d3df9f9
Refactors ini overrides.
AlliBalliBaba Jan 15, 2025
1df0c9b
formatting.
AlliBalliBaba Jan 15, 2025
e51c07d
Changes TODO.
AlliBalliBaba Jan 15, 2025
d43f6f0
trigger
AlliBalliBaba Jan 15, 2025
9c1c8a8
linting
AlliBalliBaba Jan 15, 2025
825735a
Resets Caddyfile.
AlliBalliBaba Jan 15, 2025
7de0972
phpIniOverrides -> phpIni
AlliBalliBaba Jan 16, 2025
54b28ac
Removes admin endpoints to PUT and DELETE threads.
AlliBalliBaba Jan 16, 2025
0bba5f6
Puts MaxThreads for tests back in.
AlliBalliBaba Jan 16, 2025
bace48c
Uses gomaxprocs instead.
AlliBalliBaba Jan 16, 2025
a43d2c0
Adjusts docs.
AlliBalliBaba Jan 16, 2025
7614435
Uses go's monotonic clock instead.
AlliBalliBaba Jan 16, 2025
32a3129
Removes unused func.
AlliBalliBaba Jan 16, 2025
d189010
Removes old notations.
AlliBalliBaba Jan 16, 2025
32517fe
Locks the thread handler on debug status.
AlliBalliBaba Jan 16, 2025
1d899db
Locks the thread handler on debug status.
AlliBalliBaba Jan 16, 2025
9a83ab1
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Jan 22, 2025
b3fd756
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Jan 27, 2025
e3d38b5
go fmt
AlliBalliBaba Jan 27, 2025
755551a
Makes scale chan nil if scaling is not active.
AlliBalliBaba Jan 27, 2025
2135354
locks before modification.
AlliBalliBaba Jan 27, 2025
69597ef
Fixes race condition on restarts in tests.
AlliBalliBaba Jan 27, 2025
57a1343
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Jan 30, 2025
16e8169
Resets the opcache more safely.
AlliBalliBaba Feb 1, 2025
c038273
trigger build
AlliBalliBaba Feb 1, 2025
064a368
Starts all threads as inactive.
AlliBalliBaba Feb 2, 2025
60b437f
Properly removes autoscaled threads.
AlliBalliBaba Feb 2, 2025
4a5cfd1
Fix.
AlliBalliBaba Feb 2, 2025
954ac9e
Marks a single thread to call opcache_reset.
AlliBalliBaba Feb 2, 2025
3085a65
Marks a single thread to call opcache_reset.
AlliBalliBaba Feb 2, 2025
a1f89e3
Resets opcache_reset logic.
AlliBalliBaba Feb 2, 2025
6544a73
Downloads specific watcher version.
AlliBalliBaba Feb 4, 2025
7a4aab2
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Feb 5, 2025
4668112
Fixes linting.
AlliBalliBaba Feb 5, 2025
1b945f7
Fixes linting.
AlliBalliBaba Feb 5, 2025
deec7ee
Adds suggestions by @dunglas.
AlliBalliBaba Feb 5, 2025
a9b1f44
Removes linux tag.
AlliBalliBaba Feb 5, 2025
a8ea845
Fixes linting.
AlliBalliBaba Feb 5, 2025
4e03be1
Turns the debug state into json.
AlliBalliBaba Feb 5, 2025
8325a4a
Adds php.ini block notation.
AlliBalliBaba Feb 7, 2025
9801f24
Adds loglevel check.
AlliBalliBaba Feb 7, 2025
7adc465
Removes sleep.
AlliBalliBaba Feb 7, 2025
9560e9f
Adjusts test to work without opcache.
AlliBalliBaba Feb 7, 2025
aaceaa8
Removes unnecessary bool.
AlliBalliBaba Feb 16, 2025
96c34b4
Adds more experimental warnings.
AlliBalliBaba Feb 16, 2025
319f61c
Removes request locking.
AlliBalliBaba Feb 16, 2025
b72df13
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Feb 16, 2025
7ff6322
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Feb 18, 2025
4bf5b9b
Merge branch 'main' into feat/auto-scale-clock-time
AlliBalliBaba Feb 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/watcher/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ runs:
name: Compile e-dant/watcher
run: |
mkdir watcher
gh release download --repo e-dant/watcher -A tar.gz -O - | tar -xz -C watcher --strip-components 1
gh release download 0.13.2 --repo e-dant/watcher -A tar.gz -O - | tar -xz -C watcher --strip-components 1
cd watcher
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
Expand Down
65 changes: 65 additions & 0 deletions caddy/admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package caddy

import (
"encoding/json"
"fmt"
"github.com/caddyserver/caddy/v2"
"github.com/dunglas/frankenphp"
"net/http"
)

type FrankenPHPAdmin struct{}

// if the id starts with "admin.api" the module will register AdminRoutes via module.Routes()
func (FrankenPHPAdmin) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "admin.api.frankenphp",
New: func() caddy.Module { return new(FrankenPHPAdmin) },
}
}

// EXPERIMENTAL: These routes are not yet stable and may change in the future.
func (admin FrankenPHPAdmin) Routes() []caddy.AdminRoute {
return []caddy.AdminRoute{
{
Pattern: "/frankenphp/workers/restart",
Handler: caddy.AdminHandlerFunc(admin.restartWorkers),
},
{
Pattern: "/frankenphp/threads",
Handler: caddy.AdminHandlerFunc(admin.threads),
},
}
}

func (admin *FrankenPHPAdmin) restartWorkers(w http.ResponseWriter, r *http.Request) error {
if r.Method != http.MethodPost {
return admin.error(http.StatusMethodNotAllowed, fmt.Errorf("method not allowed"))
}

frankenphp.RestartWorkers()
caddy.Log().Info("workers restarted from admin api")
admin.success(w, "workers restarted successfully\n")

return nil
}

func (admin *FrankenPHPAdmin) threads(w http.ResponseWriter, r *http.Request) error {
debugState := frankenphp.DebugState()
prettyJson, err := json.MarshalIndent(debugState, "", " ")
if err != nil {
return admin.error(http.StatusInternalServerError, err)
}

return admin.success(w, string(prettyJson))
}

func (admin *FrankenPHPAdmin) success(w http.ResponseWriter, message string) error {
w.WriteHeader(http.StatusOK)
_, err := w.Write([]byte(message))
return err
}

func (admin *FrankenPHPAdmin) error(statusCode int, err error) error {
return caddy.APIError{HTTPStatus: statusCode, Err: err}
}
215 changes: 215 additions & 0 deletions caddy/admin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package caddy_test

import (
"encoding/json"
"io"
"net/http"
"sync"
"testing"

"github.com/caddyserver/caddy/v2/caddytest"
"github.com/dunglas/frankenphp"
"github.com/stretchr/testify/assert"
)

func TestRestartWorkerViaAdminApi(t *testing.T) {
tester := caddytest.NewTester(t)
tester.InitServer(`
{
skip_install_trust
admin localhost:2999
http_port `+testPort+`

frankenphp {
worker ../testdata/worker-with-counter.php 1
}
}

localhost:`+testPort+` {
route {
root ../testdata
rewrite worker-with-counter.php
php
}
}
`, "caddyfile")

tester.AssertGetResponse("http://localhost:"+testPort+"/", http.StatusOK, "requests:1")
tester.AssertGetResponse("http://localhost:"+testPort+"/", http.StatusOK, "requests:2")

assertAdminResponse(t, tester, "POST", "workers/restart", http.StatusOK, "workers restarted successfully\n")

tester.AssertGetResponse("http://localhost:"+testPort+"/", http.StatusOK, "requests:1")
}

func TestShowTheCorrectThreadDebugStatus(t *testing.T) {
tester := caddytest.NewTester(t)
tester.InitServer(`
{
skip_install_trust
admin localhost:2999
http_port `+testPort+`

frankenphp {
num_threads 3
max_threads 6
worker ../testdata/worker-with-counter.php 1
worker ../testdata/index.php 1
}
}

localhost:`+testPort+` {
route {
root ../testdata
rewrite worker-with-counter.php
php
}
}
`, "caddyfile")

debugState := getDebugState(t, tester)

// assert that the correct threads are present in the thread info
assert.Equal(t, debugState.ThreadDebugStates[0].State, "ready")
assert.Contains(t, debugState.ThreadDebugStates[1].Name, "worker-with-counter.php")
assert.Contains(t, debugState.ThreadDebugStates[2].Name, "index.php")
assert.Equal(t, debugState.ReservedThreadCount, 3)
assert.Len(t, debugState.ThreadDebugStates, 3)
}

func TestAutoScaleWorkerThreads(t *testing.T) {
wg := sync.WaitGroup{}
maxTries := 10
requestsPerTry := 200
tester := caddytest.NewTester(t)
tester.InitServer(`
{
skip_install_trust
admin localhost:2999
http_port `+testPort+`

frankenphp {
max_threads 10
num_threads 2
worker ../testdata/sleep.php 1
}
}

localhost:`+testPort+` {
route {
root ../testdata
rewrite sleep.php
php
}
}
`, "caddyfile")

// spam an endpoint that simulates IO
endpoint := "http://localhost:" + testPort + "/?sleep=2&work=1000"
amountOfThreads := len(getDebugState(t, tester).ThreadDebugStates)

// try to spawn the additional threads by spamming the server
for tries := 0; tries < maxTries; tries++ {
wg.Add(requestsPerTry)
for i := 0; i < requestsPerTry; i++ {
go func() {
tester.AssertGetResponse(endpoint, http.StatusOK, "slept for 2 ms and worked for 1000 iterations")
wg.Done()
}()
}
wg.Wait()

amountOfThreads = len(getDebugState(t, tester).ThreadDebugStates)
if amountOfThreads > 2 {
break
}
}

// assert that there are now more threads than before
assert.NotEqual(t, amountOfThreads, 2)
}

// Note this test requires at least 2x40MB available memory for the process
func TestAutoScaleRegularThreadsOnAutomaticThreadLimit(t *testing.T) {
wg := sync.WaitGroup{}
maxTries := 10
requestsPerTry := 200
tester := caddytest.NewTester(t)
tester.InitServer(`
{
skip_install_trust
admin localhost:2999
http_port `+testPort+`

frankenphp {
max_threads auto
num_threads 1
php_ini memory_limit 40M # a reasonable limit for the test
}
}

localhost:`+testPort+` {
route {
root ../testdata
php
}
}
`, "caddyfile")

// spam an endpoint that simulates IO
endpoint := "http://localhost:" + testPort + "/sleep.php?sleep=2&work=1000"
amountOfThreads := len(getDebugState(t, tester).ThreadDebugStates)

// try to spawn the additional threads by spamming the server
for tries := 0; tries < maxTries; tries++ {
wg.Add(requestsPerTry)
for i := 0; i < requestsPerTry; i++ {
go func() {
tester.AssertGetResponse(endpoint, http.StatusOK, "slept for 2 ms and worked for 1000 iterations")
wg.Done()
}()
}
wg.Wait()

amountOfThreads = len(getDebugState(t, tester).ThreadDebugStates)
if amountOfThreads > 1 {
break
}
}

// assert that there are now more threads present
assert.NotEqual(t, amountOfThreads, 1)
}

func assertAdminResponse(t *testing.T, tester *caddytest.Tester, method string, path string, expectedStatus int, expectedBody string) {
adminUrl := "http://localhost:2999/frankenphp/"
r, err := http.NewRequest(method, adminUrl+path, nil)
assert.NoError(t, err)
if expectedBody == "" {
_ = tester.AssertResponseCode(r, expectedStatus)
return
}
_, _ = tester.AssertResponse(r, expectedStatus, expectedBody)
}

func getAdminResponseBody(t *testing.T, tester *caddytest.Tester, method string, path string) string {
adminUrl := "http://localhost:2999/frankenphp/"
r, err := http.NewRequest(method, adminUrl+path, nil)
assert.NoError(t, err)
resp := tester.AssertResponseCode(r, http.StatusOK)
defer resp.Body.Close()
bytes, err := io.ReadAll(resp.Body)
assert.NoError(t, err)

return string(bytes)
}

func getDebugState(t *testing.T, tester *caddytest.Tester) frankenphp.FrankenPHPDebugState {
threadStates := getAdminResponseBody(t, tester, "GET", "threads")

var debugStates frankenphp.FrankenPHPDebugState
err := json.Unmarshal([]byte(threadStates), &debugStates)
assert.NoError(t, err)

return debugStates
}
Loading
Loading