You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bug(connections): async race condition in connection pools (Postgres, MySQL, SQLite) creates duplicate sockets and leaks orphaned entries #275
В пулах соединений (PostgresConnectionPool, MysqlConnectionPool, SqliteConnectionPool) проверка наличия активного соединения в _pool[k] и асинхронное создание нового соединения (await createAndConnect(...)) не синхронизированы между собой:
var entry = _pool[k];
if (entry !=null) { ... returnPgLease._(...); }
...
final conn =awaitcreateAndConnect(row, database: database, mode: mode);
entry =_PoolEntry(conn)..refs =1;
_pool[k] = entry;
Поскольку вызов createAndConnect выполняется асинхронно (занимая до нескольких сотен миллисекунд на установку TCP/TLS сокета), если за это время приходит второй параллельный запрос acquire(...) для того же ключа k, он также видит _pool[k] == null и запускает повторное создание соединения.
В результате оба вызова открывают отдельные сокеты. Последний завершившийся вызов перезаписывает _pool[k] = entry, оставляя соединение от первого вызова сиротой (orphaned): его счетчик ссылок (refs) сбивается, оно больше никогда не вернется в пул и не будет закрыто при вызове _release(k), приводя к утечке сокетов в ОС.
Scope & Component
Scope:desktop
Component:Core / Connections Pool
Kind:bug
Severity:high
Detected in version:dev / 0.5.0
Местоположение в коде
Файлы:
lib/core/database/postgres_connection_pool.dart (строки ~68-94, метод acquire)
lib/core/database/mysql_connection_pool.dart (строки ~64-82, метод acquire)
lib/core/database/sqlite_connection_pool.dart (строки ~66-89, метод acquire)
Шаги воспроизведения
Запустить два параллельных асинхронных запроса на получение соединения (acquire) для одной и той же базы данных/ключа до того, как установится первое соединение (например, при одновременной загрузке вкладок или быстром клике по дереву объектов).
Проверить количество установленных TCP-соединений с сервером БД (netstat или pg_stat_activity).
Фактический результат: Создаются два (или более) физических сокета для одного ключа пула. При закрытии вкладок одно из соединений остается висеть в netstat навсегда.
Ожидаемый результат: Пул должен отслеживать выполняющиеся в данный момент асинхронные попытки подключения (Map<String, Future<_PoolEntry>> _pendingAcquires), чтобы параллельные запросы дожидались уже инициированного createAndConnect вместо повторного открытия сокетов.
Acceptance Criteria / Критерии приемки
В PostgresConnectionPool, MysqlConnectionPool и SqliteConnectionPool добавлен механизм учета in-flight (в процессе подключения) запросов по ключу k.
Если acquire(...) вызывается во время активного выполнения createAndConnect для того же ключа, второй вызов ожидает завершения первой Future и использует созданное соединение.
Написаны unit-тесты, проверяющие отсутствие дублирующих вызовов createAndConnect при конкурентном вызове acquire для одного ключа.
Activity
fix(connections): serialize concurrent pool acquire for the same key (#…
ZhuchkaTriplesix commentedon Jul 10, 2026
Fixed in #285.
fix(connections): serialize concurrent pool acquire for the same key (#…
fix(connections): serialize concurrent pool acquire for the same key (#…