Ранний ответ
oxphp_finish_request() немедленно отправляет клиенту полный HTTP-ответ и позволяет вашему PHP-скрипту продолжить работу для выполнения фоновых задач. Это аналог fastcgi_finish_request() из PHP-FPM в OxPHP.
Как это работает
- Формирование ответа. Ваш скрипт как обычно устанавливает заголовки, код состояния и выводит тело ответа через echo.
- Завершение запроса. Вызовите
oxphp_finish_request(). OxPHP сбрасывает все буферы вывода, помечает запрос как завершённый и доставляет клиенту полный HTTP-ответ. - Выполнение фоновой работы. Скрипт продолжает выполняться для фоновых задач, таких как отправка писем, запись записей в кэш или рассылка вебхуков.
- Последующий вывод отбрасывается. Любой вывод, сформированный после вызова (
echo,print,var_dump), молча отбрасывается. - Вызов идемпотентен.
oxphp_finish_request()возвращаетtrueпри первом вызове иfalseпри любом последующем вызове в рамках того же запроса.
Сценарии использования
Ранний ответ полезен всякий раз, когда нужно немедленно подтвердить приём запроса, отложив некритичную работу:
- Отправка писем — сразу верните «принято» и отправьте письмо в фоне
- Прогрев кэша — ответьте закэшированными данными, а затем перегенерируйте запись кэша
- Аналитика и логирование — подтвердите запрос, а затем запишите подробные аналитические записи
- Рассылка вебхуков — подтвердите получение вызывающей стороне, а затем разошлите доставки вебхуков
- Обработка изображений — сразу верните URL, а затем обработайте полноразмерное изображение
Примеры на 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
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
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
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
});Учитывайте время фоновой обработки при определении размера пула воркеров. Воркер, тратящий 3 секунды на работу после ответа после каждого запроса, фактически обслуживает меньше конкурентных запросов.
Устранение неполадок
Фоновая работа не завершается
PHP-настройка max_execution_time продолжает действовать и после вызова oxphp_finish_request(). Если суммарное время выполнения скрипта, включая фоновую работу, превышает лимит, запрос отменяется с фатальной ошибкой Request cancelled (timeout).
Решение: увеличьте max_execution_time (в php.ini или через set_time_limit() из скрипта) либо переместите длительные фоновые задачи в очередь сообщений:
set_time_limit(300);
oxphp_finish_request();
// ... long-running work ...Для работы, которая регулярно занимает больше нескольких секунд, публикуйте сообщение в Redis, RabbitMQ или похожую очередь и позволяйте выделенному потребителю обрабатывать его асинхронно.
Изменения сессии теряются
Данные сессии должны быть записаны до вызова oxphp_finish_request(). Изменения, сделанные после вызова, отбрасываются.
Решение: вызовите session_write_close() перед oxphp_finish_request():
<?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()и другим встроенным функциям