Wczesna odpowiedź
oxphp_finish_request() natychmiast wysyła klientowi kompletną odpowiedź HTTP i pozwala skryptowi PHP działać dalej, wykonując pracę w tle. To odpowiednik fastcgi_finish_request() z PHP-FPM w OxPHP.
Jak to działa
- Zbuduj odpowiedź. Skrypt ustawia nagłówki, kod statusu i wypisuje treść odpowiedzi jak zwykle.
- Zakończ żądanie. Wywołaj
oxphp_finish_request(). OxPHP opróżnia wszystkie bufory wyjścia, oznacza żądanie jako zakończone i dostarcza klientowi kompletną odpowiedź HTTP. - Wykonaj pracę w tle. Skrypt kontynuuje działanie na potrzeby pracy w tle, takiej jak wysyłanie e-maili, zapisywanie wpisów do pamięci podręcznej czy rozsyłanie webhooków.
- Późniejsze wyjście jest odrzucane. Każde wyjście wygenerowane po wywołaniu (
echo,print,var_dump) jest po cichu odrzucane. - Wywołanie jest idempotentne.
oxphp_finish_request()zwracatrueprzy pierwszym wywołaniu ifalseprzy każdym kolejnym wywołaniu w obrębie tego samego żądania.
Przypadki użycia
Wczesna odpowiedź przydaje się zawsze, gdy chcesz natychmiast potwierdzić żądanie, odkładając niekrytyczną pracę na później:
- Wysyłanie e-maili — od razu zwróć „accepted", a e-mail wyślij w tle
- Rozgrzewanie pamięci podręcznej — odpowiedz danymi z pamięci podręcznej, a następnie odtwórz jej wpis
- Analityka i logowanie — potwierdź żądanie, a następnie zapisz szczegółowe rekordy analityczne
- Rozsyłanie webhooków — potwierdź odbiór wywołującemu, a następnie rozdystrybuuj dostarczenia webhooków
- Przetwarzanie obrazów — od razu zwróć adres URL, a następnie przetwórz obraz w pełnym rozmiarze
Przykłady w PHP
Podstawowe użycie
<?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);Zabezpieczenie przed podwójnym wywołaniem
oxphp_finish_request() zwraca false przy drugim i kolejnych wywołaniach. Sprawdzaj wartość zwracaną w aplikacjach bogatych w middleware, gdzie tę funkcję może wywoływać wiele warstw:
<?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();
}Warunkowa praca w tle
<?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 normallyTryb worker
W trybie worker worker PHP pozostaje zajęty do momentu ukończenia całego skryptu (włącznie z całą pracą w tle). Worker nie przyjmuje nowego żądania, dopóki callback nie zwróci wyniku.
<?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
});Uwzględnij czas przetwarzania w tle przy doborze rozmiaru puli workerów. Worker, który po każdym żądaniu spędza 3 sekundy na pracy po odpowiedzi, w praktyce obsługuje mniej równoczesnych żądań.
Rozwiązywanie problemów
Praca w tle nie kończy się
Ustawienie max_execution_time w PHP nadal obowiązuje po wywołaniu oxphp_finish_request(). Jeśli całkowity czas wykonania skryptu, wliczając pracę w tle, przekroczy limit, żądanie zostaje anulowane błędem krytycznym Request cancelled (timeout).
Rozwiązanie: Zwiększ max_execution_time (w php.ini lub przez set_time_limit() w skrypcie) albo przenieś długotrwałe zadania w tle do kolejki komunikatów:
set_time_limit(300);
oxphp_finish_request();
// ... long-running work ...W przypadku pracy, która regularnie trwa dłużej niż kilka sekund, opublikuj komunikat do Redis, RabbitMQ lub podobnej kolejki i pozwól, aby dedykowany konsument obsłużył go asynchronicznie.
Po wysłaniu odpowiedzi nie da się uruchomić sesji
oxphp_finish_request() wysyła odpowiedź w jej bieżącym stanie (status, nagłówki i treść), a nic, co zostanie do niej dodane później, nie zostanie wysłane. Wysłanie odpowiedzi oznacza też, że nagłówki zostały już wysłane, a w takiej sytuacji PHP odmawia uruchomienia sesji: session_start() zgłasza Session cannot be started after headers have already been sent i zwraca false, a session_regenerate_id() odmawia w ten sam sposób. Sesja w ogóle się nie uruchamia, więc zapisy do $_SESSION od tego miejsca trafiają do zwykłej tablicy, której nic nie zapisuje. We frameworku, który zamienia ostrzeżenia na wyjątki, ta odmowa staje się wyjątkiem rzuconym wewnątrz żądania, na które już odpowiedziano.
Rozwiązanie: uruchom sesję przed wywołaniem i przed wywołaniem ją też zamknij, tak aby zapis i zwolnienie blokady nastąpiły w miejscu, które kontrolujesz:
<?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 ...W trybie worker warto tak robić niezależnie od tego, czy żądanie kończy się wcześniej. Worker zamyka sesję na końcu żądania tylko wtedy, gdy żadne inne obsługiwane przez niego żądanie nie korzysta z tej sesji; sesja współdzielona zostaje zamknięta dopiero wtedy, gdy worker będzie miał chwilę bezczynności, by ją oddać. Do tego czasu save handler nadal trzyma wszystko, co zablokował, a w przypadku domyślnego handlera jest to blokada wyłączna, która uniemożliwia komukolwiek innemu odczyt tej sesji. Pełną granicę opisuje Tryb worker.
Treść odpowiedzi jest pusta po wywołaniu oxphp_finish_request()
Jeśli wywołasz oxphp_finish_request() przed jakimkolwiek wyjściem echo, klient otrzyma pustą treść. Najpierw zbuduj i wypisz odpowiedź, a dopiero potem wywołaj funkcję.
Uwagi
oxphp_finish_request()zwracatrueprzy pierwszym wywołaniu ifalseprzy kolejnych wywołaniach w obrębie tego samego żądania.- Całe wyjście (
echo,print,var_dump) po pierwszym wywołaniu jest po cichu odrzucane. - W trybie worker worker pozostaje zajęty do momentu ukończenia całego callbacka, włącznie z całym kodem wykonywanym po odpowiedzi.
- Limit czasu żądania nadal obowiązuje kod w tle działający po
oxphp_finish_request(). oxphp_finish_request()ioxphp_stream_flush()wzajemnie się wykluczają: wywołanieoxphp_finish_request()przed rozpoczęciem strumienia uniemożliwia strumieniowanie, a wywołanie go pooxphp_stream_flush()zamyka strumień.
Prompty dla Twojego agenta
Te prompty zakładają agenta z podłączonym serwerem MCP dokumentacji OxPHP — sam przeczyta strony, których potrzebuje.
Przenieś moją pracę wykonywaną po odpowiedzi za `oxphp_finish_request()`. Przeczytaj stronę `features/early-response` przez serwer MCP dokumentacji OxPHP.
Znajdź w tym repozytorium pracę, na którą klient czeka, choć jej nie potrzebuje (wysyłkę e-maili, rozsyłanie webhooków, zapisy analityczne), i pokaż mi te handlery przepisane tak, by odpowiedź wychodziła pierwsza, a ewentualna sesja była uruchamiana i zamykana przed wywołaniem.Zobacz także
- Tryb worker — trwałe workery PHP oraz sposób, w jaki wczesna odpowiedź współdziała z pętlą żądań
- Limity czasu — jak limit czasu żądania stosuje się do pracy w tle
- Funkcje PHP — pełna dokumentacja
oxphp_finish_request()i innych funkcji wbudowanych