Рання відповідь
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() надсилає відповідь у тому вигляді, в якому вона є (статус, заголовки й тіло), і все, що додано до неї згодом, уже не надсилається. Надсилання також означає, що заголовки вже відправлено, а після цього PHP відмовляється розпочинати сесію: session_start() видає Session cannot be started after headers have already been sent і повертає false, а session_regenerate_id() відмовляє так само. Сесія взагалі не розпочинається, тож записи в $_SESSION після цього моменту потрапляють у звичайний масив, який ніхто не зберігає. У фреймворку, що перетворює попередження на винятки, відмова стає винятком, кинутим усередині запиту, на який уже дано відповідь.
Рішення: розпочніть сесію до виклику і так само закрийте її до виклику, щоб запис і зняття блокування відбулися в момент, який ви контролюєте:
<?php
session_start(); // Before the response goes out, not after
$_SESSION['last_seen'] = time();
session_write_close(); // Persist the session and release the save handler's lock
oxphp_finish_request(); // Send response
// ... work that no longer has a session ...У режимі воркерів так варто робити незалежно від того, чи завершується запит достроково. Воркер закриває сесію наприкінці запиту, лише якщо жоден інший запит, який він обслуговує, не перебуває в цій сесії; спільна сесія закривається тільки тоді, коли в цього воркера наступного разу з’явиться вільна мить, щоб її повернути. Доти обробник збереження й далі утримує все, що заблокував, а для обробника за замовчуванням це ексклюзивне блокування, через яке ніхто інший не може прочитати цю сесію. Повний опис цієї межі — у розділі Режим воркерів.
Тіло відповіді порожнє після виклику 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()закриває потік.
Промпти для вашого агента
Ці промпти розраховані на агента з підключеним MCP-сервером документації OxPHP — потрібні сторінки він прочитає сам.
Перенеси мою роботу після відповіді за `oxphp_finish_request()`. Прочитай сторінку `features/early-response` через MCP-сервер документації OxPHP.
Знайди в цьому репозиторії роботу, на яку клієнт чекає, але яка йому не потрібна (пошта, розсилання вебхуків, запис аналітики), і покажи мені ці обробники, переписані так, щоб відповідь надсилалася першою, а будь-яка сесія розпочиналася й закривалася до виклику.Див. також
- Режим воркерів — постійні PHP-воркери та взаємодія ранньої відповіді з циклом запитів
- Тайм-аути — як тайм-аут запиту поширюється на фонову роботу
- Функції PHP — повний довідник з
oxphp_finish_request()та інших вбудованих функцій