Cитуация: клиент отправил запрос к вашему api, ждёт ответ, а тебе нужно сделать что-то тяжёлое. Отправить письмо, обработать видео, записать логи в базу.
Клиент сидит и ждёт. Секунды идут. Потом ещё идут.
А можно сделать так, чтобы клиент получил ответ мгновенно, а тяжёлая работа продолжилась в фоне. Без очередей, без кронов, без лишних телодвижений.
Тут нам поможет функция PHP fastcgi_finish_request()
🎯 Что это за функция
fastcgi_finish_request() - закрывает соединение с клиентом, отдаёт ему все накопленные данные, но при этом PHP-процесс продолжает работать.
Функция появилась в PHP 5.3.3. Работает только со связкой PHP-FPM. Ещё есть LiteSpeed, но я с ним не работал. Если у тебя Apache с mod_php - не сработает.
📦 Как это выглядит в коде
<?php
// Отдаём клиенту всё, что накопили
echo json_encode(['status' => 'ok']);
// Закрываем соединение
fastcgi_finish_request();
// Дальше всё, что выполняется - уже без клиента
sleep(10); // клиент об этом не узнает
file_put_contents('/tmp/log.txt', 'Тяжёлая работа завершена');
Клиент получил ответ мгновенно, а сервер спокойно доделывает свои дела.
⚠️ Но есть нюансы (куда же без них)
1. Процесс не освобождается сразу
После вызова функции PHP-процесс продолжает висеть. Если у тебя много таких запросов - быстро упрёшься в pm.max_children и получишь 502-ю ошибку.
Как лечить: не используй для реально долгих задач. Отправить письмо - ок. Конвертировать 5 минут видео - нет.
2. Сессии блокируются
Если у тебя открыта сессия, следующий запрос от этого же пользователя будет ждать, пока сессия не закроется. Даже после вызова fastcgi_finish_request().
Ловил эту проблему, когда зависали запросы клиентов во время работы с админ-панелью. Переоткрытие вкладки в браузере не помогало. Каждый следующий запрос и новая вкладка просто висели в ожидании.
Причина оказалась простой: сессия была заблокирована фоновым процессом, который продолжал выполняться после fastcgi_finish_request().
Как лечить: вызывай
session_write_close()доfastcgi_finish_request().
session_write_close();
fastcgi_finish_request();
// теперь сессия не блокирует следующие запросы
3. Таймауты всё ещё работают
max_execution_time продолжает тикать. Если твой фоновый код выполняется дольше - будет ошибка.
Как лечить: Эти ограничения не стоит убирать, timeout не просто так выставляются. Ошибки c timeout нужно фиксировать и устранять причину длительного выполнения процесса.
🎯 Итог
fastcgi_finish_request() - удобная штука для небольших фоновых задач, когда не хочется поднимать очереди. Но с нагрузкой нужно быть осторожным.
👇 А ты используешь эту функцию? Или предпочитаешь очереди?
Обсудить пост:
- Telegram → https://t.me/buriy_dev
- ВКонтакте → https://vk.com/buriy_dev
- Max → https://max.ru/id616507661604_biz
🔥 И не забудь подписаться :)