Класс Worker
OxPHP\Server\Worker — это единый runtime-дескриптор для всего, что связано с одним OS-потоком воркера OxPHP. Это финальная (final) обёртка без состояния над thread-local-состоянием моста (bridge), регистрируемая самим SAPI-расширением, поэтому она всегда доступна как в традиционном режиме, так и в режиме воркеров. Каждый вызов читает актуальное состояние напрямую из runtime; сам объект ничего не кэширует.
Worker::current() возвращает синглтон для каждого OS-потока: два вызова в одном и том же потоке всегда возвращают один и тот же экземпляр.
Краткий справочник
| Метод | Описание |
|---|---|
Worker::current(): self |
Возвращает синглтон-дескриптор для текущего OS-потока. |
Worker::isWorkerMode(): bool |
Возвращает true, если сервер работает в режиме воркеров (то есть WORKER_MODE_ENABLED=true). |
id(): int |
Числовой идентификатор воркера в диапазоне 0..N-1 для текущего OS-потока. |
startTime(): float |
Unix-таймстамп (в секундах) момента, когда был порождён этот OS-поток воркера. |
requestCount(): int |
Счётчик запросов (начиная с 1), обработанных этим OS-потоком. Растёт в обоих режимах. |
memoryUsage(): int |
Текущее потребление памяти PHP в байтах (zend_memory_usage(0)). |
rss(): int |
Размер резидентного набора (RSS) процесса в байтах. Не кэшируется — вызывайте не более одного раза за запрос. |
maxMemoryBytes(): int |
Настроенный лимит памяти в байтах. 0 означает отсутствие ограничения. |
scheduleExit(): void |
Помечает воркер для корректного завершения работы после того, как завершится текущий запрос. В традиционном режиме ничего не делает (no-op). |
isExitScheduled(): bool |
Возвращает true, если для текущего воркера был вызван scheduleExit(). В традиционном режиме всегда false. |
exitReason(): ?string |
Причина ожидающего завершения: 'scheduled', 'max_memory', 'error' или null, когда завершение не запланировано. В традиционном режиме всегда null. |
serve(callable $h): void |
Входит в цикл обработки запросов. Вне режима воркеров выбрасывает InvalidServeContextException. |
Матрица режимов
| Метод | Традиционный режим | Режим воркеров |
|---|---|---|
current() |
Синглтон на каждый OS-поток. | Синглтон на каждый OS-поток. |
isWorkerMode() |
false |
true |
id() |
Индекс OS-потока в пуле воркеров. | Индекс OS-потока в пуле воркеров. |
startTime() |
Время порождения OS-потока (обычно момент запуска сервера). | Время порождения OS-потока. |
requestCount() |
Начиная с 1, увеличивается по мере поступления запросов, переиспользующих один и тот же OS-поток (1, 2, 3, …). |
Начиная с 1, увеличивается на каждый обработанный воркером запрос. |
memoryUsage() |
Текущая память PHP на момент вызова. | Текущая память PHP на момент вызова. |
rss() |
Текущий RSS процесса. | Текущий RSS процесса. |
maxMemoryBytes() |
0 (лимит пересоздания не применяется). |
Значение WORKER_MAX_MEMORY_MIB × 1 MiB или 0, если не задано. |
scheduleExit() |
Ничего не делает (no-op) (скрипт всё равно завершается). | Устанавливает флаг завершения; цикл обработки запросов останавливается после того, как текущий обработчик вернёт управление. |
isExitScheduled() |
Всегда false. |
true после того, как в этом потоке был вызван scheduleExit(). |
exitReason() |
Всегда null. |
null, пока завершение не запланировано; затем одно из 'scheduled', 'max_memory', 'error'. |
serve(callable) |
Выбрасывает OxPHP\Server\Exception\InvalidServeContextException. |
Входит в цикл обработки запросов. |
Примеры
Контекст логирования для каждого воркера
Помечайте каждую строку лога идентификатором воркера и счётчиком запросов по потоку, чтобы можно было соотнести трафик запросов с конкретным воркером.
<?php
$worker = OxPHP\Server\Worker::current();
$logger->info('handling request', [
'worker_id' => $worker->id(),
'request_number' => $worker->requestCount(),
]);Однократная инициализация на каждый OS-поток
requestCount() начинается с 1, поэтому первый запрос, обрабатываемый любым потоком, видит значение 1. Это переносимое место для запуска ленивой инициализации на уровне потока, которая должна выполниться ровно один раз.
<?php
$worker = OxPHP\Server\Worker::current();
if ($worker->requestCount() === 1) {
bootstrap();
}scheduleExit
Пересоздание воркеров под управлением приложения. Текущий запрос завершается штатно; после этого цикл проверяет isExitScheduled() и выходит из него. Супервизор порождает новый воркер, повторно выполняя внешнюю область видимости файла воркера.
<?php
$worker = OxPHP\Server\Worker::current();
handleRequest();
// Reload bootstrap on every request when developing locally.
if (getenv('OXPHP_DEV') === '1') {
$worker->scheduleExit();
}scheduleExit() идемпотентен и вне режима воркеров ничего не делает (no-op). Сценарии использования:
-
Горячая перезагрузка при разработке. Завершайте воркер после каждого запроса, чтобы инициализация во внешней области видимости запускалась заново.
-
Пересоздание на основе RSS.
WORKER_MAX_MEMORY_MIBучитывает только аллокатор Zend. При стеках с большим числом расширений (curl, mysqli) можно дополнительно пересоздавать воркер, когда RSS процесса пересекает ваш собственный порог:if ($worker->rss() > 256 * 1024 * 1024) { $worker->scheduleExit(); } -
Координированные поэтапные перезапуски. Ставьте вызов в зависимость от файла-сигнала (sentinel) или сигнала, чтобы внешний оркестратор мог корректно выводить воркеры из работы.
Входная точка воркера
В bootstrap-скрипте воркера вызовите serve(), чтобы войти в цикл обработки запросов.
<?php
require __DIR__ . '/../vendor/autoload.php';
OxPHP\Server\Worker::current()->serve(function () {
handleRequest();
});Наблюдаемость RSS
rss() возвращает текущий размер резидентного набора (RSS) процесса в байтах. Вызов представляет собой реальный системный вызов: дешёвый, но не бесплатный. Читайте его не более одного раза за запрос.
<?php
$worker = OxPHP\Server\Worker::current();
$rss = $worker->rss();
$metrics->gauge('php_worker_rss_bytes', $rss, [
'worker_id' => (string) $worker->id(),
]);Миграция с функций oxphp_*
Устаревшие свободные функции по-прежнему доступны и работают через то же внутреннее состояние. Они не объявлены устаревшими (deprecated). В новом коде предпочтительнее использовать API класса — ради обнаруживаемости и единообразия.
| Устаревшая функция | API класса |
|---|---|
oxphp_is_worker() |
OxPHP\Server\Worker::isWorkerMode() |
oxphp_worker_id() |
OxPHP\Server\Worker::current()->id() |
oxphp_worker(callable) |
OxPHP\Server\Worker::current()->serve(callable) |
Оговорки
rss()не кэшируется. Каждый вызов выполняет системный вызов (чтение/proc/self/statmв Linux,getrusage(RUSAGE_SELF)в macOS). Дёшево, но не бесплатно, поэтому вызывайте его не более одного раза за запрос — обычно внутри обработчика метрик, а не в каждой строке лога.- Клонирование запрещено.
clone $workerвыбрасывает\Error("Cloning OxPHP\\Server\\Worker is not allowed"). Дескриптор воркера представляет идентичность OS-потока; его клонирование создало бы обманчивое впечатление, будто существует второй дескриптор для того же потока. - Вне хоста OxPHP (например, когда расширение, линкующее SAPI, загружено в PHP CLI)
Worker::current()по-прежнему возвращает экземпляр, но каждый аксессор возвращает своё значение нулевого состояния:id()равно0,startTime()— время запуска процесса,requestCount()равно0,rss()— текущий RSS, аserve()выбрасываетInvalidServeContextException.
Смотрите также
- Режим воркеров — обзор персистентных PHP-процессов и паттерна однократной инициализации
- Функции PHP — справочник по устаревшим свободным функциям
oxphp_* - API запросов —
OxPHP\Http\RequestInterface::startTime()для замера времени по каждому запросу