Ранний ответ

oxphp_finish_request() немедленно отправляет клиенту полный HTTP-ответ и позволяет вашему PHP-скрипту продолжить работу для выполнения фоновых задач. Это аналог fastcgi_finish_request() из PHP-FPM в OxPHP.

Как это работает

  1. Формирование ответа. Ваш скрипт как обычно устанавливает заголовки, код состояния и выводит тело ответа через echo.
  2. Завершение запроса. Вызовите oxphp_finish_request(). OxPHP сбрасывает все буферы вывода, помечает запрос как завершённый и доставляет клиенту полный HTTP-ответ.
  3. Выполнение фоновой работы. Скрипт продолжает выполняться для фоновых задач, таких как отправка писем, запись записей в кэш или рассылка вебхуков.
  4. Последующий вывод отбрасывается. Любой вывод, сформированный после вызова (echo, print, var_dump), молча отбрасывается.
  5. Вызов идемпотентен. oxphp_finish_request() возвращает true при первом вызове и false при любом последующем вызове в рамках того же запроса.

Сценарии использования

Ранний ответ полезен всякий раз, когда нужно немедленно подтвердить приём запроса, отложив некритичную работу:

  • Отправка писем — сразу верните «принято» и отправьте письмо в фоне
  • Прогрев кэша — ответьте закэшированными данными, а затем перегенерируйте запись кэша
  • Аналитика и логирование — подтвердите запрос, а затем запишите подробные аналитические записи
  • Рассылка вебхуков — подтвердите получение вызывающей стороне, а затем разошлите доставки вебхуков
  • Обработка изображений — сразу верните URL, а затем обработайте полноразмерное изображение

Примеры на PHP

Базовое использование

php
<?php header('Content-Type: application/json'); echo json_encode(['status' => 'accepted', 'id' => uniqid()]); // Send response now — client receives the full response at this point oxphp_finish_request(); // Background work runs here; client is no longer waiting file_put_contents('/tmp/audit.log', date('c') . " request processed\n", FILE_APPEND); send_notification_email($user);

Защита от двойного вызова

oxphp_finish_request() возвращает false при втором и последующих вызовах. Проверяйте возвращаемое значение в приложениях с большим количеством middleware, где несколько слоёв могут вызвать эту функцию:

php
<?php function finish_and_cleanup(): void { if (!oxphp_finish_request()) { // Already finished — background work was already scheduled return; } // First call — safe to run cleanup flush_metrics_buffer(); close_external_connections(); }

Условная фоновая работа

php
<?php header('Content-Type: application/json'); $payload = json_decode(file_get_contents('php://input'), true); $result = handle_request($payload); echo json_encode($result); if ($result['needs_sync']) { oxphp_finish_request(); sync_to_external_service($result); } // No early finish if sync is not needed — script exits normally

Режим воркеров

В режиме воркеров PHP-воркер остаётся занятым до тех пор, пока не завершится весь скрипт (включая всю фоновую работу). Воркер не принимает новый запрос, пока не вернётся колбэк.

php
<?php oxphp_worker(function () { $order = json_decode(file_get_contents('php://input'), true); $result = process_order($order); header('Content-Type: application/json'); echo json_encode(['order_id' => $result['id'], 'status' => 'accepted']); oxphp_finish_request(); // Worker is still occupied during this background work send_confirmation_email($result); update_inventory($result); notify_warehouse($result); // Worker becomes available after this point });
Note

Учитывайте время фоновой обработки при определении размера пула воркеров. Воркер, тратящий 3 секунды на работу после ответа после каждого запроса, фактически обслуживает меньше конкурентных запросов.

Устранение неполадок

Фоновая работа не завершается

PHP-настройка max_execution_time продолжает действовать и после вызова oxphp_finish_request(). Если суммарное время выполнения скрипта, включая фоновую работу, превышает лимит, запрос отменяется с фатальной ошибкой Request cancelled (timeout).

Решение: увеличьте max_execution_timephp.ini или через set_time_limit() из скрипта) либо переместите длительные фоновые задачи в очередь сообщений:

php
set_time_limit(300); oxphp_finish_request(); // ... long-running work ...

Для работы, которая регулярно занимает больше нескольких секунд, публикуйте сообщение в Redis, RabbitMQ или похожую очередь и позволяйте выделенному потребителю обрабатывать его асинхронно.

Изменения сессии теряются

Данные сессии должны быть записаны до вызова oxphp_finish_request(). Изменения, сделанные после вызова, отбрасываются.

Решение: вызовите session_write_close() перед oxphp_finish_request():

php
<?php $_SESSION['last_seen'] = time(); session_write_close(); // Persist session before finishing oxphp_finish_request(); // Send response
Тело ответа пустое после вызова oxphp_finish_request()

Если вы вызываете oxphp_finish_request() до какого-либо вывода через echo, клиент получает пустое тело. Сначала сформируйте и выведите ответ, а затем вызывайте функцию.

Примечания

  • oxphp_finish_request() возвращает true при первом вызове и false при последующих вызовах в рамках того же запроса.
  • Весь вывод (echo, print, var_dump) после первого вызова молча отбрасывается.
  • В режиме воркеров воркер остаётся занятым до полного завершения колбэка, включая весь код после ответа.
  • Таймаут запроса продолжает применяться к фоновому коду, выполняемому после oxphp_finish_request().
  • oxphp_finish_request() и oxphp_stream_flush() взаимоисключающи: вызов oxphp_finish_request() до начала стрима не даёт запустить стриминг, а вызов после oxphp_stream_flush() закрывает стрим.

См. также

  • Режим воркеров — постоянные PHP-процессы и то, как ранний ответ взаимодействует с циклом обработки запросов
  • Таймауты — как таймаут запроса применяется к фоновой работе
  • PHP-функции — полный справочник по oxphp_finish_request() и другим встроенным функциям