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

  1. Zbuduj odpowiedź. Skrypt ustawia nagłówki, kod statusu i wypisuje treść odpowiedzi jak zwykle.
  2. 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.
  3. 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.
  4. Późniejsze wyjście jest odrzucane. Każde wyjście wygenerowane po wywołaniu (echo, print, var_dump) jest po cichu odrzucane.
  5. Wywołanie jest idempotentne. oxphp_finish_request() zwraca true przy pierwszym wywołaniu i false przy 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
<?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
<?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
<?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

Tryb 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
<?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

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:

php
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.

Zmiany w sesji są tracone

Dane sesji muszą zostać zapisane przed wywołaniem oxphp_finish_request(). Zmiany wprowadzone po wywołaniu są odrzucane.

Rozwiązanie: Wywołaj session_write_close() przed oxphp_finish_request():

php
<?php $_SESSION['last_seen'] = time(); session_write_close(); // Persist session before finishing oxphp_finish_request(); // Send response
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() zwraca true przy pierwszym wywołaniu i false przy 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() i oxphp_stream_flush() wzajemnie się wykluczają: wywołanie oxphp_finish_request() przed rozpoczęciem strumienia uniemożliwia strumieniowanie, a wywołanie go po oxphp_stream_flush() zamyka strumień.

Zobacz także

  • Tryb worker — trwałe procesy 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