Класс 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
<?php $worker = OxPHP\Server\Worker::current(); $logger->info('handling request', [ 'worker_id' => $worker->id(), 'request_number' => $worker->requestCount(), ]);

Однократная инициализация на каждый OS-поток

requestCount() начинается с 1, поэтому первый запрос, обрабатываемый любым потоком, видит значение 1. Это переносимое место для запуска ленивой инициализации на уровне потока, которая должна выполниться ровно один раз.

php
<?php $worker = OxPHP\Server\Worker::current(); if ($worker->requestCount() === 1) { bootstrap(); }

scheduleExit

Пересоздание воркеров под управлением приложения. Текущий запрос завершается штатно; после этого цикл проверяет isExitScheduled() и выходит из него. Супервизор порождает новый воркер, повторно выполняя внешнюю область видимости файла воркера.

php
<?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 процесса пересекает ваш собственный порог:

    php
    if ($worker->rss() > 256 * 1024 * 1024) { $worker->scheduleExit(); }
  • Координированные поэтапные перезапуски. Ставьте вызов в зависимость от файла-сигнала (sentinel) или сигнала, чтобы внешний оркестратор мог корректно выводить воркеры из работы.

Входная точка воркера

В bootstrap-скрипте воркера вызовите serve(), чтобы войти в цикл обработки запросов.

php
<?php require __DIR__ . '/../vendor/autoload.php'; OxPHP\Server\Worker::current()->serve(function () { handleRequest(); });

Наблюдаемость RSS

rss() возвращает текущий размер резидентного набора (RSS) процесса в байтах. Вызов представляет собой реальный системный вызов: дешёвый, но не бесплатный. Читайте его не более одного раза за запрос.

php
<?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() для замера времени по каждому запросу