Uh oh!
There was an error while loading. Please reload this page.
feat: worker matching - #1646
Conversation
withinboredom
commented
Jun 11, 2025
I think I prefer the latter of the two options, but I can see the benefits of the first one too. |
AlliBalliBaba
commented
Jun 11, 2025
Thinking about it, the first option makes it maybe clearer that this is only possible inside of |
FYI, you might want to explore using pprof's I think this is the syntax
You could do 1v2 and 1v3 to easily see where and how much the difference is |
AlliBalliBaba
commented
Jun 11, 2025
I've managed to create a differential flamegraph via this guide # first profile
go tool pprof -raw -output=cpu1.txt 'http://localhost:2019/debug/pprof/profile?seconds=20'#second profile
go tool pprof -raw -output=cpu2.txt 'http://localhost:2019/debug/pprof/profile?seconds=20'# diff flamegraph
./stackcollapse-go.pl ./cpu1.txt > out.folded1
./stackcollapse-go.pl ./cpu2.txt > out.folded2
./difffolded.pl -n out.folded2 out.folded1 | ./flamegraph.pl > /go/src/app/flamegraph.svgA bit hard to make out what's the difference between 'red' and 'blue' though |
henderkes
commented
Jun 12, 2025
I'm very strongly in favour of option one, simply because it will allow the match to behave in a general scope, such as for assets (php_server also has a file_server built in, it would also benefit) as well. |
AlliBalliBaba
commented
Jun 12, 2025
@henderkes what would php_server {
match/path1/* worker /anywhere/worker1.php match/path2/* worker /anywhere/worker2.php match/assets/* fileserver
}
# if nothing matches continue to the next directive |
henderkes
commented
Jun 12, 2025
If /assets/some_asset.png isn't found, it should 404 of course. But that's the same as falling through to the default behaviour of file_server, is it not? |
AlliBalliBaba
commented
Jun 12, 2025
I mean if it matches neither of the paths |
henderkes
commented
Jun 12, 2025
oh, then it should fall through to the default behaviour. |
AlliBalliBaba
commented
Jun 12, 2025
Hmm makes sense, so the order would be:
|
henderkes
commented
Jun 12, 2025
I was thinking more along the lines of
|
Hmm I'm still not sure about The reason the |
That would be quite confusing and might also hurt performance of regularly handled requests, because it has to go through all global workers and try to match the path, even if it was never intended and never produces a match.
But not with the match directive. It's an explicit tell that all routes with /path1/* should be handled by the worker. There absolutely doesn't and shouldn't be a file_server involved with that at all. If a user configures route {
@assets path /path1* handle@assets {
rewriteworker1.php php
}
}and then expects an image in that path1 to be served by a file server.
That's pretty much what it would be. The reason it should exist is something like this: php_server {
match/path1/images/* file_server
match/path1/* worker worker1.php
}And that's also what I envision the What I think would happen when a php_server (or php) directive is hit in pseudocode: (FrankenPHPModule*f) handleRequest(httpRequestr) {
path:=r.URL.Pathforpattern, handlerinrangef.matches {
ifpathmatchespatternhandler(r)
}
// fallthrough to current logic
}
|
AlliBalliBaba
commented
Jun 13, 2025
This would not work since we would never hit the php module via
While I can see the benefit of an abbreviation like this, it wouldn't cover the most common use case, which is So I'm still a bit torn, but now leaning more towards the worker->match direction, also because the implementation is simpler. php_server {
worker {
file/anywhere/worker.php match* }
} |
henderkes
commented
Jun 13, 2025
In that case match ... file_server really doesn't make sense. Unless we were to register a different directive, but that's exactly what I wanted to avoid.
If serving files is always tried before our php module handler is even hit, wouldn't the equivalent just be php_server {
match/path1/* worker worker1.php// fall back to normal logic to see if we can match against a worker or use a regular php thread
}
I really don't like the other way around. It just doesn't make sense. The worker doesn't perform any matching, the worker should never even be queried if it didn't match the request. |
AlliBalliBaba
commented
Jun 13, 2025
Yeah these 2 would be equivalent, depends on how you think about it and how this might be extended in the future php_server {
match/path/* worker /anywhere/worker.php
}php_server {
worker {
file/anywhere/worker.php match/path/*
}
} |
d3d8405 to
b8ad01aCompare
dunglas
left a comment
There was a problem hiding this comment.
Is this one ready to be merged? Could you add some docs?
AlliBalliBaba
commented
Jun 27, 2025
Yes I think this one is ready to merge. I'll add some docs (in this PR or a separate one, whichever you prefer) |
…nkenphp into feat/worker-matching # Conflicts: # caddy/module.go # caddy/workerconfig.go # frankenphp.go # phpmainthread_test.go # worker.go
AlliBalliBaba
commented
Jun 28, 2025
Docs are added 👍 |
Uh oh!
There was an error while loading. Please reload this page.
dunglas
commented
Jun 30, 2025
Could you please rebase @AlliBalliBaba? |
# Conflicts: # caddy/workerconfig.go # phpmainthread_test.go # worker.go
…nkenphp into feat/worker-matching
AlliBalliBaba
commented
Jun 30, 2025
Merged 👍 |
dunglas
commented
Jul 1, 2025
Great work, thank you! Regarding the GitHub issue, I discussed with the PHP team, and they are reluctant to add 2 accounts for the same person. Would you prefer that we remove @AlliBalliBaba and add @AlliBalliBaba2 instead? |
AlliBalliBaba
commented
Jul 1, 2025
Hmm yeah maybe this account is just irreversibly broken and I'll have to migrate over to @Alliballibaba2, all of these github support issues didn't really go anywhere |
AlliBalliBaba
commented
Jul 3, 2025
Nevermind, just got feedback that actions work again 🎉 |
This one is interesting — though I’m not sure the best way to provide a test. I will have to look into maybe an integration test because it is a careful dance between how we resolve paths in the Caddy module vs. workers. I looked into making a proper change (literally using the same logic everywhere), but I think it is best to wait until #1646 is merged. But anyway, this change deals with some interesting edge cases. I will use gherkin to describe them: ```gherkin Feature: FrankenPHP symlinked edge cases Background: Given a `test` folder And a `public` folder linked to `test` And a worker script located at `test/index.php` And a `test/nested` folder And a worker script located at `test/nested/index.php` Scenario: neighboring worker script Given frankenphp located in the test folder When I execute `frankenphp php-server --listen localhost:8080 -w index.php` from `public` Then I expect to see the worker script executed successfully Scenario: nested worker script Given frankenphp located in the test folder When I execute `frankenphp --listen localhost:8080 -w nested/index.php` from `public` Then I expect to see the worker script executed successfully Scenario: outside the symlinked folder Given frankenphp located in the root folder When I execute `frankenphp --listen localhost:8080 -w public/index.php` from the root folder Then I expect to see the worker script executed successfully Scenario: specified root directory Given frankenphp located in the root folder When I execute `frankenphp --listen localhost:8080 -w public/index.php -r public` from the root folder Then I expect to see the worker script executed successfully ``` Trying to write that out in regular English would be more complex IMHO. These scenarios should all pass now with this PR. --------- Signed-off-by: Marc <m@pyc.ac> Co-authored-by: henderkes <m@pyc.ac> Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
This is an alternative to #1552. instead of having a new directive, this introduces a way to match workers against paths, therefore allowing placing the worker anywhere outside of the public directory..
wip
not sure yet if this is better:
or this:
performance:
default

php_serverwihworkerphp_serverwihworkerandtry_files {path} index.phpphp_serverwihworkerandmatch *(minimizes file operations)