Production
Examples
Every example of this topic, with its output.
StopReason#
use Swerve\ClientRequest;
use Swerve\RequestHandler;
use Swerve\StopReason;
use Swerve\WorkerStoppingException;
$app = new RequestHandler(function (ClientRequest $request) {
$request->write("waiting for news\n");
try {
phasync::sleep(30);
} catch (WorkerStoppingException $e) {
phasync::shielded(fn () => $request->write(match ($e->reason) {
StopReason::Shutdown => "the server is going away\n",
StopReason::Reload => "new code is starting: reconnect\n",
StopReason::Recycle => "this worker is replaced: reconnect\n",
}));
}
});
if (debug_backtrace()) {
return $app; // swerve loads this file: it is the application's swerve.php
}
// Run directly: serve the application with swerve, and send it requests
require __DIR__ . '/../serve.php';
serve(__FILE__, ["GET /news HTTP/1.1\r\nHost: example\r\n\r\n"], stop: SIGHUP); // a reload, once it answersOutput
HTTP/1.1 200 OK Server: Swerve Transfer-Encoding: chunked Connection: close 11 waiting for news 20 new code is starting: reconnect 0
Swerve::log#
use Swerve\Swerve;
// Outside swerve's command line, log() is a NullLogger until setLog() is called
echo get_class(Swerve::log()), "\n";
Swerve::log()->error('nobody sees this');
// It is the same object on every call: hand it to libraries that take a PSR-3 logger
var_dump(Swerve::log() === Swerve::log());Output
Psr\Log\NullLogger bool(true)
Swerve::log#
Swerve::log()->warning('disk almost full: {free} MB', ['free' => $free]);Swerve::setLog#
use Psr\Log\AbstractLogger;
use Swerve\Swerve;
// Any PSR-3 logger; this one prints each line
Swerve::setLog(new class () extends AbstractLogger {
public function log($level, string|Stringable $message, array $context = []): void
{
echo "[$level] $message ", json_encode($context), "\n";
}
});
Swerve::log()->info('started');
Swerve::log()->warning('disk almost full: {free} MB', ['free' => 512]);Output
[info] started []
[warning] disk almost full: {free} MB {"free":512}Swerve::setLog#
Swerve::setLog(new Monolog\Logger('app'));Swerve::draining#
use Swerve\ClientRequest;
use Swerve\RequestHandler;
use Swerve\Swerve;
use Swerve\WebSocket;
$app = new RequestHandler(function (ClientRequest $request) {
WebSocket::from($request, function (WebSocket $ws) {
Swerve::onShutdown(fn () => phasync::shielded(function () use ($ws) {
$ws->send('draining: ' . var_export(Swerve::draining(), true));
$ws->end(1001);
}));
$ws->send('draining: ' . var_export(Swerve::draining(), true));
foreach ($ws as $message) {
}
});
});
if (debug_backtrace()) {
return $app; // swerve loads this file: it is the application's swerve.php
}
// Run directly: serve the application with swerve, and talk to it as a browser would
require __DIR__ . '/../serve.php';
websocket(__FILE__, '/live', [], stop: SIGTERM); // swerve is stopped after the first messageOutput
HTTP/1.1 101 Switching Protocols upgrade: websocket connection: Upgrade sec-websocket-accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Server: Swerve < draining: false < draining: true < close 1001
Swerve::draining#
while (!Swerve::draining()) {
$out->append(": keep-alive\n\n");
phasync::sleep(15);
}Swerve::onShutdown#
use Swerve\ClientRequest;
use Swerve\RequestHandler;
use Swerve\Swerve;
use Swerve\WebSocket;
$app = new RequestHandler(function (ClientRequest $request) {
WebSocket::from($request, function (WebSocket $ws) {
// When the worker must close its connections: say why, in the protocol
Swerve::onShutdown(fn () => phasync::shielded(fn () => $ws->end(1001, 'server restarting')));
$ws->send('welcome');
foreach ($ws as $message) {
$ws->send($message);
}
});
});
if (debug_backtrace()) {
return $app; // swerve loads this file: it is the application's swerve.php
}
// Run directly: serve the application with swerve, and talk to it as a browser would
require __DIR__ . '/../serve.php';
websocket(__FILE__, '/live', [], stop: SIGTERM); // swerve is stopped after the welcomeOutput
HTTP/1.1 101 Switching Protocols upgrade: websocket connection: Upgrade sec-websocket-accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Server: Swerve < welcome < close 1001 server restarting
Swerve::onShutdown#
YourProtocol::from($request, function (YourProtocol $conn) {
Swerve::onShutdown(fn () => phasync::shielded(fn () => $conn->end('restarting')));
foreach ($conn as $message) {
$conn->send(handle($message));
}
});Swerve::awaitShutdown#
use Swerve\ClientRequest;
use Swerve\RequestHandler;
use Swerve\Swerve;
$app = new RequestHandler(function (ClientRequest $request) {
// false when the timeout passes first
$request->write('must close within 0.1 s: ' . var_export(Swerve::awaitShutdown(0.1), true) . "\n");
});
if (debug_backtrace()) {
return $app; // swerve loads this file: it is the application's swerve.php
}
// Run directly: serve the application with swerve, and send it requests
require __DIR__ . '/../serve.php';
serve(__FILE__, ["GET / HTTP/1.1\r\nHost: example\r\n\r\n"]);Output
HTTP/1.1 200 OK Server: Swerve Transfer-Encoding: chunked Connection: close 1f must close within 0.1 s: false 0
Swerve::awaitShutdown#
if (Swerve::awaitShutdown(30)) {
$ws->end(1001);
}Swerve::ini#
Swerve::ini(['memory_limit' => '512M']);Swerve::onWorkerStart#
// a file in your package's composer.json "files"
Swerve::onWorkerStart(function () {
phasync::go(function () {
while (true) {
refresh_feature_flags();
phasync::sleep(60);
}
});
});Swerve::getVersion#
use Swerve\Swerve;
// The installed version of phasync/swerve, as Composer knows it
echo 'swerve ', Swerve::getVersion(), "\n";Output
swerve 0.1.0
WorkerStoppingException#
use Swerve\ClientRequest;
use Swerve\RequestHandler;
use Swerve\WorkerStoppingException;
$app = new RequestHandler(function (ClientRequest $request) {
$request->write("export started\n");
try {
phasync::sleep(30); // a long job; the worker stops meanwhile
$request->write("export done\n");
} catch (WorkerStoppingException $e) {
// Clean up at once; a write waits, so it goes inside shielded()
phasync::shielded(fn () => $request->write("stopped: {$e->reason->name}, try again\n"));
}
});
if (debug_backtrace()) {
return $app; // swerve loads this file: it is the application's swerve.php
}
// Run directly: serve the application with swerve, and send it requests
require __DIR__ . '/../serve.php';
serve(__FILE__, ["GET /export HTTP/1.1\r\nHost: example\r\n\r\n"], stop: SIGTERM); // stop swerve once it answersOutput
HTTP/1.1 200 OK Server: Swerve Transfer-Encoding: chunked Connection: close f export started 1d stopped: Shutdown, try again 0