Quickstart
Start an application in Classic mode. Then convert it to Worker mode. Store the settings in a configuration file. The steps require a rapira binary with its bundled PHP. See Installation for more information.
Classic mode
Classic mode is available to every application. Rapira includes the entry script again for every request, as php-fpm does. The code does not need to change.
Create public/index.php:
<?php
header('Content-Type: text/plain');
echo "Hello, " . ($_GET['name'] ?? 'anonymous') . "!\n";
echo "Method: {$_SERVER['REQUEST_METHOD']}\n";Create rapira.toml next to the public directory. The mode key selects Classic mode, and entrypoint names the entry script:
[http]
listen = "127.0.0.1:8000"
[http.pool]
entrypoint = "public/index.php"
mode = "classic"Start the server with the path to the file:
rapira serve rapira.tomlRapira binds 127.0.0.1:8000. Send a request from another terminal:
curl '127.0.0.1:8000/?name=world'Hello, world!
Method: GETWorker processes stay active between requests. Rapira creates the workers once and keeps an initialized PHP interpreter in each worker. Classic mode removes the script state after each request. This state includes variables, the autoloader, and framework objects.
Worker mode
Worker mode keeps the script active. The script initializes once and then waits for requests in a loop. For each request, Rapira fills the superglobals again and calls the handler. PHP can still read $_GET and use echo for a response. See Execution modes for more information.
Create worker.php in the project root:
<?php
// This value remains available for each request in this worker.
$handled = 0;
$handler = static function () use (&$handled): void {
$handled++;
header('Content-Type: text/plain');
echo "Hello, " . ($_GET['name'] ?? 'anonymous') . "!\n";
echo "worker " . getmypid() . " handled {$handled} request(s)\n";
};
while (\Rapira\handle_request($handler)) {
gc_collect_cycles();
}\Rapira\handle_request() waits for the next request. It calls the handler and returns true. During worker shutdown, \Rapira\handle_request() returns false. This value ends the loop.
The handler reads superglobals and creates output with echo and header(). Call \Rapira\handle_request() only from the top-level script loop. It throws Rapira\Exception\NotInWorkerModeError in other modes.
The PHP module that Rapira registers provides \Rapira\handle_request(). Thus, the example needs no autoloader. An application with Composer dependencies must load vendor/autoload.php before the loop.
Stop the Classic server with Ctrl-C because both servers bind 127.0.0.1:8000. Change rapira.toml to Worker mode:
[http]
listen = "127.0.0.1:8000"
[http.pool]
entrypoint = "worker.php"
mode = "worker"rapira serve rapira.tomlcurl '127.0.0.1:8000/?name=world'Run the curl command several times. A worker's counter increases when that process handles another request. By default, Rapira sets the worker count from the available CPUs. The operating system selects a worker for each connection. Each worker has a separate count. The output process identifier shows which worker returned the response.
Set processes = 1 in [http.pool] to create one worker. See process model for pool supervision.
Objects created before the while loop remain in memory until the worker script restarts. Examples include the Composer autoloader, container, connections, routes, and templates. Rapira initializes this state once instead of for each request. Only request state is new in each iteration.
The worker script must reset request state that remains in memory. Examples include static properties, global values, and open transactions. See Worker mode for more information.
The handler can call rapira_finish_request() to send the response before the handler ends. See HTTP for more information.
Configuration file
The configuration file holds every setting. The rapira serve command accepts only the path to this file. To use four workers, add processes = 4 to the existing [http.pool] table.
A relative http.pool.entrypoint uses the configuration file directory as its base. The current directory does not affect it.
The file also controls worker replacement, request timeouts, logging, and the supervisor pidfile. The server does not start if the file contains an unknown key. See Configuration for all configuration file settings and CLI for the command.
Stopping the server
Press Ctrl-C to stop the server. The terminal sends SIGINT to the master and to each worker, so current requests stop immediately. To let current requests finish, send SIGTERM only to the master process, for example kill -TERM <master-pid>. See Process model for the complete signal table.
Next steps
- Worker mode describes the persistent loop, state, memory leaks, worker replacement, and application initialization.
- Configuration lists each
rapira.tomlkey and its default. - Frameworks provides integration guides for Symfony, Laravel, and Yii3.