Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: prove that Fibers work if not calling Go #229

Merged
merged 1 commit into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ containing [PHP 8.2](https://www.php.net/releases/8.2/en.php) and most popular P
* [Docker images](docs/docker.md)
* [Compile from sources](docs/compile.md)
* [Create static binaries](docs/static.md)
* [Known issues](docs/known-issues.md)
* [Demo app (Symfony) and benchmarks](https://github.com/dunglas/frankenphp-demo)
* [Go library documentation](https://pkg.go.dev/github.com/dunglas/frankenphp)
* [Contributing and debugging](CONTRIBUTING.md)
Expand Down
32 changes: 32 additions & 0 deletions docs/known-issues.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Known Issues

## Fibers

Calling PHP functions and language constructs that themselves call [cgo](https://go.dev/blog/cgo) in [Fibers](https://www.php.net/manual/en/language.fibers.php) is known to cause crashes.

This issue [is being worked on by the Go project](https://github.com/golang/go/issues/62130).


In the meantime, one solution is not to use constructs (like `echo`) and functions (like `header()`) that delegate to Go from inside Fibers.

This code will likely crash because it uses `echo` in the Fiber:

```php
$fiber = new Fiber(function() {
echo 'In the Fiber'.PHP_EOL;
echo 'Still inside'.PHP_EOL;
});
$fiber->start();
```

Instead, return the value from the Fiber and use it outside:

```php
$fiber = new Fiber(function() {
Fiber::suspend('In the Fiber'.PHP_EOL));
Fiber::suspend('Still inside'.PHP_EOL));
});
echo $fiber->start();
echo $fiber->resume();
$fiber->resume();
```
17 changes: 17 additions & 0 deletions frankenphp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -571,3 +571,20 @@ func ExampleServeHTTP() {
})
log.Fatal(http.ListenAndServe(":8080", nil))
}

func TestFiberNoCgo_module(t *testing.T) { testFiberNoCgo(t, &testOptions{}) }
func TestFiberNonCgo_worker(t *testing.T) {
testFiberNoCgo(t, &testOptions{workerScript: "fiber-no-cgo.php"})
}
func testFiberNoCgo(t *testing.T, opts *testOptions) {
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/fiber-no-cgo.php?i=%d", i), nil)
w := httptest.NewRecorder()
handler(w, req)

resp := w.Result()
body, _ := io.ReadAll(resp.Body)

assert.Equal(t, string(body), fmt.Sprintf("Fiber %d", i))
}, opts)
}
12 changes: 12 additions & 0 deletions testdata/fiber-no-cgo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php
require_once __DIR__.'/_executor.php';

return function() {
$fiber = new Fiber(function() {
Fiber::suspend('Fiber '.($_GET['i'] ?? ''));
});
echo $fiber->start();

$fiber->resume();
};