Réponse anticipée
oxphp_finish_request() envoie immédiatement la réponse HTTP complète au client et laisse votre script PHP continuer de s'exécuter pour effectuer un travail en arrière-plan. C'est l'équivalent OxPHP de fastcgi_finish_request() dans PHP-FPM.
Fonctionnement
- Construire la réponse. Votre script définit les en-têtes, le code de statut et émet le corps de la réponse comme d'habitude.
- Terminer la requête. Appelez
oxphp_finish_request(). OxPHP vide tous les tampons de sortie, marque la requête comme terminée et délivre la réponse HTTP complète au client. - Exécuter le travail en arrière-plan. Le script poursuit son exécution pour effectuer un travail en arrière-plan, comme l'envoi d'e-mails, l'écriture d'entrées de cache ou l'envoi de webhooks.
- Toute sortie ultérieure est ignorée. Toute sortie produite après l'appel (
echo,print,var_dump) est silencieusement ignorée. - L'appel est idempotent.
oxphp_finish_request()renvoietrueau premier appel etfalseà tout appel ultérieur au sein de la même requête.
Cas d'usage
La réponse anticipée est utile chaque fois que vous souhaitez accuser réception d'une requête immédiatement tout en différant un travail non critique :
- Envoi d'e-mails — renvoyez « accepted » immédiatement, envoyez l'e-mail en arrière-plan
- Préchauffage du cache — répondez avec les données en cache, puis régénérez l'entrée de cache
- Analytique et journalisation — accusez réception de la requête, puis écrivez des enregistrements analytiques détaillés
- Envoi de webhooks — confirmez la réception à l'appelant, puis distribuez les livraisons de webhooks
- Traitement d'images — renvoyez une URL immédiatement, puis traitez l'image en taille réelle
Exemples PHP
Utilisation de base
<?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);Se prémunir contre le double appel
oxphp_finish_request() renvoie false au deuxième appel et aux suivants. Vérifiez la valeur de retour dans les applications riches en middleware où plusieurs couches pourraient appeler la fonction :
<?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();
}Travail en arrière-plan conditionnel
<?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 normallyMode worker
En mode worker, le worker PHP reste occupé jusqu'à ce que l'intégralité du script (y compris tout le travail en arrière-plan) soit terminée. Le worker n'accepte pas de nouvelle requête tant que le callback n'a pas retourné.
<?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
});Tenez compte du temps de traitement en arrière-plan lorsque vous dimensionnez votre pool de workers. Un worker qui passe 3 secondes en travail post-réponse après chaque requête traite en pratique moins de requêtes simultanées.
Dépannage
Le travail en arrière-plan ne se termine pas
Le paramètre max_execution_time de PHP continue de s'appliquer après l'appel de oxphp_finish_request(). Si le temps d'exécution total du script, travail en arrière-plan compris, dépasse la limite, la requête est annulée avec une erreur fatale Request cancelled (timeout).
Solution : Augmentez max_execution_time (dans php.ini ou via set_time_limit() depuis le script), ou déplacez les tâches d'arrière-plan longues vers une file de messages :
set_time_limit(300);
oxphp_finish_request();
// ... long-running work ...Pour un travail qui prend régulièrement plus de quelques secondes, publiez un message dans Redis, RabbitMQ ou une file similaire et laissez un consommateur dédié le traiter de manière asynchrone.
Impossible de démarrer une session une fois la réponse partie
oxphp_finish_request() envoie la réponse telle qu'elle est (statut, en-têtes et corps), et rien de ce qui y est ajouté ensuite n'est envoyé. L'envoyer signifie aussi que les en-têtes sont partis, et PHP refuse alors de démarrer une session : session_start() lève Session cannot be started after headers have already been sent et renvoie false, et session_regenerate_id() refuse de la même manière. La session n'est pas démarrée du tout, donc les écritures dans $_SESSION après ce point vont dans un simple tableau que rien ne sauvegarde. Avec un framework qui transforme les avertissements en exceptions, ce refus devient une exception levée dans une requête à laquelle on a déjà répondu.
Solution : démarrez la session avant l'appel, et fermez-la aussi avant l'appel, pour que l'écriture et le déverrouillage aient lieu à un moment que vous maîtrisez :
<?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 ...En mode worker, cela vaut la peine même si la requête ne se termine pas de façon anticipée. Un worker ne ferme une session en fin de requête que si aucune autre requête qu'il traite n'utilise cette session ; une session partagée n'est fermée qu'au prochain moment d'inactivité du worker, où il peut la rendre. D'ici là, le gestionnaire de sauvegarde garde tout ce qu'il a verrouillé, ce qui, pour le gestionnaire par défaut, est un verrou exclusif qui empêche quiconque de lire cette session. Voir Mode worker pour la frontière complète.
Le corps de la réponse est vide après l'appel de oxphp_finish_request()
Si vous appelez oxphp_finish_request() avant toute sortie echo, le client reçoit un corps vide. Construisez et émettez d'abord la réponse, puis appelez la fonction.
Notes
oxphp_finish_request()renvoietrueau premier appel etfalseaux appels suivants au sein de la même requête.- Toute sortie (
echo,print,var_dump) après le premier appel est silencieusement ignorée. - En mode worker, le worker reste occupé jusqu'à ce que l'intégralité du callback soit terminée, y compris tout le code post-réponse.
- Le délai d'expiration de la requête continue de s'appliquer au code d'arrière-plan qui s'exécute après
oxphp_finish_request(). oxphp_finish_request()etoxphp_stream_flush()sont mutuellement exclusifs : appeleroxphp_finish_request()avant de démarrer un flux empêche le streaming, et l'appeler aprèsoxphp_stream_flush()ferme le flux.
Prompts pour votre agent
Ces prompts supposent un agent connecté au serveur MCP de la documentation OxPHP — il lira lui-même les pages dont il a besoin.
Déplace mon travail post-réponse derrière `oxphp_finish_request()`. Lis la page `features/early-response` via le serveur MCP de la documentation OxPHP.
Trouve dans ce dépôt le travail que le client attend sans en avoir besoin (envoi d'e-mails, distribution de webhooks, écritures analytiques) et montre-moi ces gestionnaires réécrits pour que la réponse parte en premier, avec toute session démarrée et fermée avant l'appel.Voir aussi
- Mode worker — les workers PHP persistants et la façon dont la réponse anticipée interagit avec la boucle de requêtes
- Délais d'expiration — comment le délai d'expiration de la requête s'applique au travail en arrière-plan
- Fonctions PHP — référence complète de
oxphp_finish_request()et des autres fonctions intégrées