Add global payment request timeout setting

This commit is contained in:
BADtochka
2026-06-05 23:40:02 +03:00
parent 1158a2d835
commit 766f2a5780
13 changed files with 54 additions and 6 deletions
@@ -348,6 +348,16 @@ SETTINGS_MANIFEST: List[SettingField] = [
"Английская версия текста на этапе оплаты.", "Английская версия текста на этапе оплаты.",
subsection="checkout", subsection="checkout",
), ),
SettingField(
"PAYMENT_REQUEST_TIMEOUT_SECONDS",
"float",
"payments",
"Таймаут запроса к провайдеру",
"Максимальное общее время одного API-запроса к платёжному провайдеру, в секундах.",
optional=False,
min=1,
subsection="checkout",
),
# ─── Payment providers (toggles) ─────────────────────────────── # ─── Payment providers (toggles) ───────────────────────────────
# Common # Common
SettingField("STARS_ENABLED", "bool", "payments", "Telegram Stars", subsection="common"), SettingField("STARS_ENABLED", "bool", "payments", "Telegram Stars", subsection="common"),
+1 -1
View File
@@ -153,7 +153,7 @@ class FreeKassaService(HttpClientMixin):
self.default_currency: str = default_payment_currency_code_for_settings(settings).upper() self.default_currency: str = default_payment_currency_code_for_settings(settings).upper()
self.api_base_url: str = "https://api.fk.life/v1" self.api_base_url: str = "https://api.fk.life/v1"
self._init_http_client(total_timeout=15) self._init_http_client(total_timeout=self.settings.PAYMENT_REQUEST_TIMEOUT_SECONDS)
self._nonce_lock = asyncio.Lock() self._nonce_lock = asyncio.Lock()
self._last_nonce = int(time.time() * 1000) self._last_nonce = int(time.time() * 1000)
+1 -1
View File
@@ -243,7 +243,7 @@ class HeleketService(HttpClientMixin):
self.referral_service = referral_service self.referral_service = referral_service
self._default_return_url = default_return_url self._default_return_url = default_return_url
self._init_http_client(total_timeout=20) self._init_http_client(total_timeout=self.settings.PAYMENT_REQUEST_TIMEOUT_SECONDS)
if not self.configured: if not self.configured:
logging.warning( logging.warning(
"HeleketService initialized but not fully configured. Payments disabled." "HeleketService initialized but not fully configured. Payments disabled."
+1 -1
View File
@@ -369,7 +369,7 @@ class PaykillaService(HttpClientMixin):
self.referral_service = referral_service self.referral_service = referral_service
self._default_return_url = default_return_url self._default_return_url = default_return_url
self._init_http_client(total_timeout=20) self._init_http_client(total_timeout=self.settings.PAYMENT_REQUEST_TIMEOUT_SECONDS)
if not self.configured: if not self.configured:
logging.warning( logging.warning(
"PaykillaService initialized but not fully configured. Payments disabled." "PaykillaService initialized but not fully configured. Payments disabled."
+1 -1
View File
@@ -157,7 +157,7 @@ class PlategaService(HttpClientMixin):
self.referral_service = referral_service self.referral_service = referral_service
self._default_return_url = default_return_url self._default_return_url = default_return_url
self._init_http_client(total_timeout=60) self._init_http_client(total_timeout=self.settings.PAYMENT_REQUEST_TIMEOUT_SECONDS)
if not self.configured: if not self.configured:
logging.warning( logging.warning(
"PlategaService initialized but not fully configured. Payments disabled." "PlategaService initialized but not fully configured. Payments disabled."
+1 -1
View File
@@ -136,7 +136,7 @@ class SeverPayService(HttpClientMixin):
self.referral_service = referral_service self.referral_service = referral_service
self._default_return_url = default_return_url self._default_return_url = default_return_url
self._init_http_client(total_timeout=15) self._init_http_client(total_timeout=self.settings.PAYMENT_REQUEST_TIMEOUT_SECONDS)
if not self.configured: if not self.configured:
logging.warning( logging.warning(
+1 -1
View File
@@ -206,7 +206,7 @@ class WataService(HttpClientMixin):
self._default_return_url = default_return_url self._default_return_url = default_return_url
self._cached_public_key_pem = None # populated by webhook on first verify self._cached_public_key_pem = None # populated by webhook on first verify
self._init_http_client(total_timeout=10) self._init_http_client(total_timeout=self.settings.PAYMENT_REQUEST_TIMEOUT_SECONDS)
if not self.configured: if not self.configured:
logging.warning("WataService initialized but not fully configured. Payments disabled.") logging.warning("WataService initialized but not fully configured. Payments disabled.")
+5
View File
@@ -319,6 +319,11 @@ class Settings(BaseSettings):
default=DEFAULT_SUBSCRIPTION_PURCHASE_DESCRIPTION_EN, default=DEFAULT_SUBSCRIPTION_PURCHASE_DESCRIPTION_EN,
description="English subscription description shown before purchase/renewal options.", description="English subscription description shown before purchase/renewal options.",
) )
PAYMENT_REQUEST_TIMEOUT_SECONDS: float = Field(
default=20,
ge=1,
description="Maximum total time for one payment provider API request, in seconds.",
)
MONTH_1_ENABLED: bool = Field(default=True, alias="1_MONTH_ENABLED") MONTH_1_ENABLED: bool = Field(default=True, alias="1_MONTH_ENABLED")
MONTH_3_ENABLED: bool = Field(default=True, alias="3_MONTHS_ENABLED") MONTH_3_ENABLED: bool = Field(default=True, alias="3_MONTHS_ENABLED")
+1
View File
@@ -200,6 +200,7 @@
| `PAYMENT_METHODS_ORDER` | Порядок кнопок оплаты: `severpay,wata,freekassa,platega,yookassa,stars,cryptopay,heleket,paykilla`. | | `PAYMENT_METHODS_ORDER` | Порядок кнопок оплаты: `severpay,wata,freekassa,platega,yookassa,stars,cryptopay,heleket,paykilla`. |
| `SUBSCRIPTION_PURCHASE_DESCRIPTION_ENABLED` | Показывать описание подписки перед выбором срока. | | `SUBSCRIPTION_PURCHASE_DESCRIPTION_ENABLED` | Показывать описание подписки перед выбором срока. |
| `SUBSCRIPTION_PURCHASE_DESCRIPTION_RU` / `SUBSCRIPTION_PURCHASE_DESCRIPTION_EN` | Локализованное описание подписки. | | `SUBSCRIPTION_PURCHASE_DESCRIPTION_RU` / `SUBSCRIPTION_PURCHASE_DESCRIPTION_EN` | Локализованное описание подписки. |
| `PAYMENT_REQUEST_TIMEOUT_SECONDS` | Общий таймаут одного API-запроса к платёжному провайдеру, в секундах. По умолчанию `20`. |
| `PAYMENT_<METHOD>_WEBAPP_LABEL_RU` / `PAYMENT_<METHOD>_WEBAPP_LABEL_EN` | Текст кнопки провайдера в Web App. | | `PAYMENT_<METHOD>_WEBAPP_LABEL_RU` / `PAYMENT_<METHOD>_WEBAPP_LABEL_EN` | Текст кнопки провайдера в Web App. |
| `PAYMENT_<METHOD>_WEBAPP_ICON` | Lucide-иконка кнопки в Web App. | | `PAYMENT_<METHOD>_WEBAPP_ICON` | Lucide-иконка кнопки в Web App. |
| `PAYMENT_<METHOD>_TELEGRAM_LABEL_RU` / `PAYMENT_<METHOD>_TELEGRAM_LABEL_EN` | Текст кнопки в Telegram. | | `PAYMENT_<METHOD>_TELEGRAM_LABEL_RU` / `PAYMENT_<METHOD>_TELEGRAM_LABEL_EN` | Текст кнопки в Telegram. |
@@ -603,6 +603,26 @@
"overridden": false, "overridden": false,
"updated_at": null "updated_at": null
}, },
{
"key": "PAYMENT_REQUEST_TIMEOUT_SECONDS",
"type": "float",
"section": "payments",
"section_order": 4,
"subsection": "checkout",
"label": "Таймаут запроса к провайдеру",
"description": "Максимальное общее время одного API-запроса к платёжному провайдеру, в секундах.",
"i18n_label_key": "admin_settings_field_payment_request_timeout_seconds_label",
"i18n_description_key": "admin_settings_field_payment_request_timeout_seconds_description",
"i18n_subsection_key": "admin_settings_subsection_checkout",
"i18n_placeholder_key": null,
"placeholder": "",
"optional": false,
"secret": false,
"min": 1,
"value": "",
"overridden": false,
"updated_at": null
},
{ {
"key": "STARS_ENABLED", "key": "STARS_ENABLED",
"type": "bool", "type": "bool",
+3
View File
@@ -1170,6 +1170,7 @@
"admin_settings_subsection_cryptopay": "CryptoPay", "admin_settings_subsection_cryptopay": "CryptoPay",
"admin_settings_subsection_wata": "Wata", "admin_settings_subsection_wata": "Wata",
"admin_settings_subsection_heleket": "Heleket", "admin_settings_subsection_heleket": "Heleket",
"admin_settings_subsection_paykilla": "PayKilla",
"admin_settings_provider_webhook_url": "Webhook URL", "admin_settings_provider_webhook_url": "Webhook URL",
"admin_settings_provider_webhook_url_hint": "Use this URL in the provider webhook settings.", "admin_settings_provider_webhook_url_hint": "Use this URL in the provider webhook settings.",
"admin_settings_panel_webhook_url_hint": "Use this URL as WEBHOOK_URL in Remnawave Panel.", "admin_settings_panel_webhook_url_hint": "Use this URL as WEBHOOK_URL in Remnawave Panel.",
@@ -1676,6 +1677,8 @@
"admin_settings_field_subscription_purchase_description_ru_description": "Russian text shown during checkout.", "admin_settings_field_subscription_purchase_description_ru_description": "Russian text shown during checkout.",
"admin_settings_field_subscription_purchase_description_en_label": "Subscription description (EN)", "admin_settings_field_subscription_purchase_description_en_label": "Subscription description (EN)",
"admin_settings_field_subscription_purchase_description_en_description": "English text shown during checkout.", "admin_settings_field_subscription_purchase_description_en_description": "English text shown during checkout.",
"admin_settings_field_payment_request_timeout_seconds_label": "Payment provider request timeout",
"admin_settings_field_payment_request_timeout_seconds_description": "Maximum total time for one payment provider API request, in seconds.",
"admin_settings_field_stars_enabled_label": "Stars Enabled", "admin_settings_field_stars_enabled_label": "Stars Enabled",
"admin_settings_field_yookassa_enabled_label": "YooKassa Enabled", "admin_settings_field_yookassa_enabled_label": "YooKassa Enabled",
"admin_settings_field_yookassa_shop_id_label": "YooKassa Shop ID", "admin_settings_field_yookassa_shop_id_label": "YooKassa Shop ID",
+3
View File
@@ -1170,6 +1170,7 @@
"admin_settings_subsection_cryptopay": "CryptoPay", "admin_settings_subsection_cryptopay": "CryptoPay",
"admin_settings_subsection_wata": "Wata", "admin_settings_subsection_wata": "Wata",
"admin_settings_subsection_heleket": "Heleket", "admin_settings_subsection_heleket": "Heleket",
"admin_settings_subsection_paykilla": "PayKilla",
"admin_settings_provider_webhook_url": "Webhook URL", "admin_settings_provider_webhook_url": "Webhook URL",
"admin_settings_provider_webhook_url_hint": "Укажите этот адрес в настройках вебхуков провайдера.", "admin_settings_provider_webhook_url_hint": "Укажите этот адрес в настройках вебхуков провайдера.",
"admin_settings_panel_webhook_url_hint": "Укажите этот адрес как WEBHOOK_URL в Remnawave Panel.", "admin_settings_panel_webhook_url_hint": "Укажите этот адрес как WEBHOOK_URL в Remnawave Panel.",
@@ -1676,6 +1677,8 @@
"admin_settings_field_subscription_purchase_description_ru_description": "Русская версия текста на этапе оплаты.", "admin_settings_field_subscription_purchase_description_ru_description": "Русская версия текста на этапе оплаты.",
"admin_settings_field_subscription_purchase_description_en_label": "Описание подписки (EN)", "admin_settings_field_subscription_purchase_description_en_label": "Описание подписки (EN)",
"admin_settings_field_subscription_purchase_description_en_description": "Английская версия текста на этапе оплаты.", "admin_settings_field_subscription_purchase_description_en_description": "Английская версия текста на этапе оплаты.",
"admin_settings_field_payment_request_timeout_seconds_label": "Таймаут запроса к провайдеру",
"admin_settings_field_payment_request_timeout_seconds_description": "Максимальное общее время одного API-запроса к платёжному провайдеру, в секундах.",
"admin_settings_field_stars_enabled_label": "Telegram Stars", "admin_settings_field_stars_enabled_label": "Telegram Stars",
"admin_settings_field_yookassa_enabled_label": "Включена", "admin_settings_field_yookassa_enabled_label": "Включена",
"admin_settings_field_yookassa_shop_id_label": "Shop ID", "admin_settings_field_yookassa_shop_id_label": "Shop ID",
@@ -24,6 +24,7 @@ SUBSCRIPTION_PURCHASE_DESCRIPTION_SETTINGS = (
"SUBSCRIPTION_PURCHASE_DESCRIPTION_ENABLED", "SUBSCRIPTION_PURCHASE_DESCRIPTION_ENABLED",
"SUBSCRIPTION_PURCHASE_DESCRIPTION_RU", "SUBSCRIPTION_PURCHASE_DESCRIPTION_RU",
"SUBSCRIPTION_PURCHASE_DESCRIPTION_EN", "SUBSCRIPTION_PURCHASE_DESCRIPTION_EN",
"PAYMENT_REQUEST_TIMEOUT_SECONDS",
) )
SUBSCRIPTION_GUIDE_SETTINGS = ( SUBSCRIPTION_GUIDE_SETTINGS = (
@@ -177,6 +178,11 @@ def test_support_settings_i18n_keys_exist_in_admin_locales():
def test_subscription_purchase_description_settings_i18n_keys_exist(): def test_subscription_purchase_description_settings_i18n_keys_exist():
manifest = _manifest_by_key() manifest = _manifest_by_key()
timeout_field = manifest["PAYMENT_REQUEST_TIMEOUT_SECONDS"]
assert timeout_field["type"] == "float"
assert timeout_field["optional"] is False
assert timeout_field["min"] == 1
for language in ("ru", "en"): for language in ("ru", "en"):
messages = _locale(language) messages = _locale(language)
for setting_key in SUBSCRIPTION_PURCHASE_DESCRIPTION_SETTINGS: for setting_key in SUBSCRIPTION_PURCHASE_DESCRIPTION_SETTINGS: