As discussed in https://github.com/php/frankenphp/discussions/1961,
there is no real way to pass a severity/level to any log handler offered
by PHP that would make it to the FrankenPHP layer. This new function
allows applications embedding FrankenPHP to integrate PHP logging into
the application itself, thus offering a more streamlined experience.
---------
Co-authored-by: Quentin Burgess <qutn.burgess@gmail.com>
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
This patch brings hot reloading capabilities to PHP apps: in
development, the browser will automatically refresh the page when any
source file changes!
It's similar to HMR in JavaScript.
It is built on top of [the watcher
mechanism](https://frankenphp.dev/docs/config/#watching-for-file-changes)
and of the [Mercure](https://frankenphp.dev/docs/mercure/) integration.
Each time a watched file is modified, a Mercure update is sent, giving
the ability to the client to reload the page, or part of the page
(assets, images...).
Here is an example implementation:
```caddyfile
root ./public
mercure {
subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY}
anonymous
}
php_server {
hot_reload
}
```
```php
<?php
header('Content-Type: text/html');
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
<script>
const es = new EventSource('<?=$_SERVER['FRANKENPHP_HOT_RELOAD']?>');
es.onmessage = () => location.reload();
</script>
</head>
<body>
Hello
```
I plan to create a helper JS library to handle more advanced cases
(reloading CSS, JS, etc), similar to [HotWire
Spark](https://github.com/hotwired/spark). Be sure to attend my
SymfonyCon to learn more!
There is still room for improvement:
- Provide an option to only trigger the update without reloading the
worker for some files (ex, images, JS, CSS...)
- Support classic mode (currently, only the worker mode is supported)
- Don't reload all workers when only the files used by one change
However, this PR is working as-is and can be merged as a first step.
This patch heavily refactors the watcher module. Maybe it will be
possible to extract it as a standalone library at some point (would be
useful to add a similar feature but not tight to PHP as a Caddy module).
---------
Signed-off-by: Kévin Dunglas <kevin@dunglas.fr>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This PR:
- moves state.go to its own module
- moves the phpheaders test the phpheaders module
- simplifies backoff.go
- makes the backoff error instead of panic (so it can be tested)
- removes some unused C structs
* fix a memory leak on thread shutdown
* clean up unused resources at end of request
* try the obvious
* Test
* clang-format
* Also ignores persistent streams.
* Adds stream test.
* Moves clean up function to frankenphp_worker_request_shutdown.
* Fixes test on -nowatcher
* Fixes test on -nowatcher
* Update testdata/file-stream.txt
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
* Update frankenphp_test.go
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
---------
Co-authored-by: Alliballibaba <alliballibaba@gmail.com>
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
* Decouple workers.
* Moves code to separate file.
* Cleans up the exponential backoff.
* Initial working implementation.
* Refactors php threads to take callbacks.
* Cleanup.
* Cleanup.
* Cleanup.
* Cleanup.
* Adjusts watcher logic.
* Adjusts the watcher logic.
* Fix opcache_reset race condition.
* Fixing merge conflicts and formatting.
* Prevents overlapping of TSRM reservation and script execution.
* Adjustments as suggested by @dunglas.
* Adds error assertions.
* Adds comments.
* Removes logs and explicitly compares to C.false.
* Resets check.
* Adds cast for safety.
* Fixes waitgroup overflow.
* Resolves waitgroup race condition on startup.
* Moves worker request logic to worker.go.
* Removes defer.
* Removes call from go to c.
* Fixes merge conflict.
* Adds fibers test back in.
* Refactors new thread loop approach.
* Removes redundant check.
* Adds compareAndSwap.
* Refactor: removes global waitgroups and uses a 'thread state' abstraction instead.
* Removes unnecessary method.
* Updates comment.
* Removes unnecessary booleans.
* test
* First state machine steps.
* Splits threads.
* Minimal working implementation with broken tests.
* Fixes tests.
* Refactoring.
* Fixes merge conflicts.
* Formatting
* C formatting.
* More cleanup.
* Allows for clean state transitions.
* Adds state tests.
* Adds support for thread transitioning.
* Fixes the testdata path.
* Formatting.
* Allows transitioning back to inactive state.
* Fixes go linting.
* Formatting.
* Removes duplication.
* Applies suggestions by @dunglas
* Removes redundant check.
* Locks the handler on restart.
* Removes unnecessary log.
* Changes Unpin() logic as suggested by @withinboredom
* Adds suggestions by @dunglas and resolves TODO.
* Makes restarts fully safe.
* Will make the initial startup fail even if the watcher is enabled (as is currently the case)
* Also adds compareAndSwap to the test.
* Adds comment.
* Prevents panic on initial watcher startup.
* implement getenv and putenv in go
* fix typo
* apply formatting
* return a bool
* prevent ENV= from crashing
* optimization
* optimization
* split env workflows and use go_strings
* clean up unused code
* update tests
* remove useless sprintf
* see if this fixes the asan issues
* clean up comments
* check that VAR= works correctly and use actual php to validate the behavior
* move all unpinning to the end of the request
* handle the case where php is not installed
* fix copy-paste
* optimization
* use strings.cut
* fix lint
* override how env is filled
* reuse fullenv
* use corect function
* handle failures gracefully
* fix super-subtle race condition
* address feedback: panic instead of fatal log and make vars into consts
* pass the frankenphp context to worker-ready function
* reset backoff and failures on normal restart
* update docs
* add test and fix race condition
* fail sometimes but do not be pathological about it
* Use title case
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
* fix code style in php
* define lifecycle metrics
* ensure we update unregister the metrics and fix tests
* update caddy tests and fix typo
* update docs
* no need for this
---------
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
* fix: reset sapi response code
It turns out that the sapi response code is NOT reset between requests by the zend engine. This resets the code for cgi-based requests.
fixes: #960
* update response header test
* fix assertion
* appears to affect workers too