]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
fix: таймауты HTTP-запросов к Telegram API (устранение 504 на dev) origin/feature_filippov_telegram_http_timeout
authorAleksey Filippov <Aleksey.Filippov@erp-flowers.ru>
Thu, 4 Jun 2026 16:49:42 +0000 (19:49 +0300)
committerAleksey Filippov <Aleksey.Filippov@erp-flowers.ru>
Thu, 4 Jun 2026 16:49:42 +0000 (19:49 +0300)
Запросы к api.telegram.org выполнялись через Guzzle/cURL без таймаутов.
При недоступности api.telegram.org (резолвится только в IPv6, маршрута
нет) cURL виснет ~130с. Отправка идёт синхронно внутри обработки запроса
(в т.ч. из лог-таргета на каждый Yii::error), поэтому воркер PHP-FPM
блокировался, пул (max_children=5) исчерпывался и весь сайт отдавал 504.

Добавлены connect_timeout=2с и timeout=5с ко всем вызовам Telegram API
через единый клиент getHttpClient(), а также CURLOPT_CONNECTTIMEOUT/
CURLOPT_TIMEOUT в cURL-вызовах sendPromoMessageToTelegramDocument.

erp24/services/TelegramService.php

index 2b015865da6f7761bac45dd3013b2003faaa9af9..9c6da498d4e74313064074b3573bceb084a5f204 100644 (file)
@@ -20,6 +20,33 @@ class TelegramService
 
     const TARGET_PROD_URL = "erp.erp-flowers.ru";
 
+    /**
+     * Таймаут установки TCP/TLS-соединения с Telegram API (секунды).
+     *
+     * Почему важно: api.telegram.org резолвится в IPv6, и при отсутствии
+     * IPv6-маршрута cURL по умолчанию виснет ~130с. Запросы к Telegram
+     * выполняются синхронно внутри обработки HTTP-запроса (в т.ч. из
+     * лог-таргета на каждый Yii::error()), поэтому без таймаута блокируется
+     * воркер PHP-FPM, пул исчерпывается и весь сайт отдаёт 504.
+     */
+    private const CONNECT_TIMEOUT = 2;
+
+    /**
+     * Таймаут всего HTTP-запроса к Telegram API (секунды).
+     */
+    private const REQUEST_TIMEOUT = 5;
+
+    /**
+     * HTTP-клиент с обязательными таймаутами для запросов к Telegram API.
+     */
+    private static function getHttpClient(): Client
+    {
+        return new Client([
+            'connect_timeout' => self::CONNECT_TIMEOUT,
+            'timeout' => self::REQUEST_TIMEOUT,
+        ]);
+    }
+
     /**
      * Получить токен бота для dev окружения
      */
@@ -66,7 +93,7 @@ class TelegramService
         if ($reply_markup) {
             $url .= "&reply_markup=" . json_encode($reply_markup, JSON_UNESCAPED_UNICODE);
         }
-        $client = new \GuzzleHttp\Client();
+        $client = self::getHttpClient();
         return $client->request('GET', $url);
     }
 
@@ -102,7 +129,7 @@ class TelegramService
             $chatId = $chatIdErp;
         }
 
-        $client = new Client();
+        $client = self::getHttpClient();
         try {
             $client->post($apiURL, [
                 'json' => [
@@ -123,7 +150,7 @@ class TelegramService
         $apiURL = "https://api.telegram.org/bot{$botToken}/sendMessage";
         $chats = ['337084327', '730432579']; //Алексей и Владимир
         $message = self::escapeMarkdown($message);
-        $client = new Client();
+        $client = self::getHttpClient();
         foreach ($chats as $chatId) {
             try {
                 $buttons = self::getTgButtons($chatId);
@@ -199,6 +226,8 @@ class TelegramService
                 curl_setopt($ch, CURLOPT_POSTFIELDS, $arrayQuery1);
                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                 curl_setopt($ch, CURLOPT_HEADER, false);
+                curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::CONNECT_TIMEOUT);
+                curl_setopt($ch, CURLOPT_TIMEOUT, self::REQUEST_TIMEOUT);
                 $res1 = curl_exec($ch);
                 curl_close($ch);
 
@@ -217,6 +246,8 @@ class TelegramService
                 curl_setopt($ch, CURLOPT_POSTFIELDS, $arrayQuery2);
                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                 curl_setopt($ch, CURLOPT_HEADER, false);
+                curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::CONNECT_TIMEOUT);
+                curl_setopt($ch, CURLOPT_TIMEOUT, self::REQUEST_TIMEOUT);
                 $res2 = curl_exec($ch);
                 curl_close($ch);
 
@@ -257,7 +288,7 @@ class TelegramService
             try {
                 $buttons = self::getTgShortButtons($chatId);
 
-                $client = new Client();
+                $client = self::getHttpClient();
 
                 $media = [
                     [
@@ -311,7 +342,7 @@ class TelegramService
                     return $e->getMessage();
                 }
 
-                $client = new Client();
+                $client = self::getHttpClient();
 
                 try {
                     $response = $client->post($apiURL2, [
@@ -363,7 +394,7 @@ class TelegramService
         $message = self::escapeMarkdown($message);
         $buttons = self::getTgButtons($chatId);
 
-        $client = new Client();
+        $client = self::getHttpClient();
         try {
             $response = $client->post($apiURL, [
                 'json' => [