fix(exchange): isolate concurrent connection checks
All checks were successful
CI/CD Pipeline / Quality Gate (push) Successful in 42s
CI/CD Pipeline / Build and Push Images (push) Successful in 20s
CI/CD Pipeline / Internal Notify (push) Successful in 0s
CI/CD Pipeline / Deploy Dev via Compose (push) Successful in 33s

This commit is contained in:
2026-08-10 14:05:44 +02:00
parent 851549587a
commit 2a1f29983e
3 changed files with 28 additions and 3 deletions

View File

@@ -3,6 +3,7 @@
from __future__ import annotations from __future__ import annotations
import json import json
import uuid
from contextlib import suppress from contextlib import suppress
from typing import Any from typing import Any
@@ -301,7 +302,10 @@ class ExchangeConnectionService:
@classmethod @classmethod
def _configure_alias(cls, connection: ExchangeConnection) -> str: def _configure_alias(cls, connection: ExchangeConnection) -> str:
alias = f"exchange_target_{connection.id}" connection_key = (
connection.pk if connection.pk is not None else uuid.uuid4().hex
)
alias = f"exchange_target_{connection_key}"
config = { config = {
"ENGINE": "django.db.backends.postgresql", "ENGINE": "django.db.backends.postgresql",

View File

@@ -90,8 +90,8 @@ class ExchangeConnectionTestView(APIView):
tags=[EXCHANGE_TAG], tags=[EXCHANGE_TAG],
operation_summary="Проверить подключение", operation_summary="Проверить подключение",
operation_description=( operation_description=(
"Проверяет подключение и структуру целевой БД без сохранения " "Проверяет доступность PostgreSQL и учетные данные без сохранения "
"настроек подключения." "настроек подключения. Проверка структуры выполняется при сохранении."
), ),
request_body=ExchangeConnectionCreateSerializer, request_body=ExchangeConnectionCreateSerializer,
responses={ responses={

View File

@@ -505,6 +505,27 @@ class ExchangeConnectionServiceUnitTest(TestCase):
self.assertEqual(connections_mock.databases[alias]["PASSWORD"], "secret") self.assertEqual(connections_mock.databases[alias]["PASSWORD"], "secret")
self.assertNotIn(alias, storage.__dict__) self.assertNotIn(alias, storage.__dict__)
def test_configure_alias_uses_unique_alias_for_unsaved_connection(self):
connection = ExchangeConnection(
server="127.0.0.1",
port=5432,
username="postgres",
password="secret", # noqa: S106
database_name="target_db",
schema_name="public",
)
first_alias = ExchangeConnectionService._configure_alias(connection)
second_alias = ExchangeConnectionService._configure_alias(connection)
try:
self.assertNotEqual(first_alias, second_alias)
self.assertTrue(first_alias.startswith("exchange_target_"))
self.assertTrue(second_alias.startswith("exchange_target_"))
finally:
ExchangeConnectionService._cleanup_alias(first_alias)
ExchangeConnectionService._cleanup_alias(second_alias)
def test_validate_schema_exists_raises_when_schema_missing(self): def test_validate_schema_exists_raises_when_schema_missing(self):
cursor = MagicMock() cursor = MagicMock()
cursor.fetchone.return_value = None cursor.fetchone.return_value = None