Python 3.14.7: asyncio.wait очищает await-graph у pending future. Безопасный локальный A/B, контроль, измеримая матрица, критерий остановки и минимизированный пакет данных для поддержки без production-секретов.
Зафиксируйте границу изменения
Запрос этой страницы ограничен формулировкой «как проверить leak awaited_by после asyncio.wait race с pending future Python 3.14.7». Официальный changelog подтверждает только следующее изменение: после возврата asyncio.wait waiting task удаляется из awaited_by каждого future, включая так и не завершившиеся pending futures. Наблюдаемый симптом для проверки: короткие wait-races заканчиваются, но await-graph продолжает удерживать завершённые waiting tasks через вечный future. Похожий traceback, зависание или рост памяти сам по себе не доказывает эту причину. Запишите точную версию интерпретатора, платформу, начальное состояние и ожидаемый переход. Обновление рабочего окружения не является первым тестом: начните с изолированного воспроизведения.
Минимальный воспроизводимый сценарий
Рекомендуемый fixture для issue gh-152569: в новом event loop многократно гонять ready future против одного never-resolving future, после каждого wait снимать размер awaited_by через доступный introspection path. Каждый case запускайте на новом объекте, а при риске crash, hang или большого потребления ресурса — в отдельном child process. Размер input, число повторов и deadline задаются до старта. Используйте только синтетические markers, loopback, BytesIO или собственный temp root. Если нужная ОС, accelerator либо GUI backend недоступны, честный результат — environment blocker, а не отрицание исправления.
Контроль, который может опровергнуть тест
Независимая контрольная ветка: gather с явной отменой обеих задач и wait, где оба futures завершаются. Выполните порядок A, затем проблемный case B, полностью очистите состояние и снова запустите A2. Версия Python, architecture, event loop, locale и лимиты должны совпадать. Если A2 отличается от A, fixture протёк через cache, descriptor, task, environment или temp file. Такой опыт нельзя объявлять успешным, даже если B дал ожидаемое значение.
Протокол наблюдений
Заполняйте матрицу «iteration × done/pending split × waiting task state × awaited_by size × retained objects × loop warnings». Сохраняйте типы и состояния: exception class отдельно от текста, bytes length отдельно от содержимого, task state отдельно от результата, elapsed отдельно от deadline. Для процесса нужны exit code и signal, для сети — порядок accept/read/close, для parser — вход и фактическая граница. Пустой столбец означает незавершённый case. IP, usernames, токены, полные paths, environment dumps и содержимое рабочих файлов в журнал не входят.
Решение по наблюдаемому результату
Зелёный критерий узкий: после каждой итерации pending future не удерживает закончившийся waiter, а controls завершаются без pending-task warnings. Если test и control падают одинаково, сначала исправьте стенд. Если control чист, а проблемная ветка не воспроизводится, оставьте статус unknown: отсутствие эффекта в одном окружении не доказывает его невозможность. Сравнение старой версии и 3.14.7 допустимо только при одинаковом fixture. Даже тогда вывод относится к конкретной границе совместимости, а не ко всем приложениям и не к популярности запроса.
Стоп-линия и обратимость
Предметное ограничение: ограничить iterations и завершить опыт при монотонном росте; не делать вывод по одному снимку GC. Также немедленно остановитесь при внешнем соединении, записи вне temp root, неожиданном запросе прав, зависании без killable child или появлении приватных данных. Не добивайтесь зелёного статуса отключением проверки сертификатов, бесконечным retry, глобальным catch-all или увеличением ресурсных лимитов после срабатывания. После опыта: {topic['cleanup']}.
Минимальный пакет для воспроизведения
Передайте поддержке только: loop implementation, число итераций, done/pending counts, await-graph sizes, gc control и warnings. Добавьте московский timestamp, точную команду запуска с synthetic input, строки A/B/A2 и ожидаемый критерий. Замените абсолютные paths на labels, удалите PIDs, hostnames, email, реальные архивы, базы и memory dumps. Получатель должен повторить один state transition без доступа к вашей инфраструктуре. Если без production-файла воспроизведение невозможно, пакет ещё не минимизирован и не готов к отправке.
Почему это отдельный ответ gh-152569
Самостоятельность задаёт связка intent «как проверить leak awaited_by после asyncio.wait race с pending future Python 3.14.7», пользовательская боль «короткие wait-races заканчиваются, но await-graph продолжает удерживать завершённые waiting tasks через вечный future», подтверждённая boundary «после возврата asyncio.wait waiting task удаляется из awaited_by каждого future, включая так и не завершившиеся pending futures», fixture «в новом event loop многократно гонять ready future против одного never-resolving future, после каждого wait снимать размер awaited_by через доступный introspection path» и критерий «после каждой итерации pending future не удерживает закончившийся waiter, а controls завершаются без pending-task warnings». Она не сводится к смене ОС или имени модуля: меняются наблюдаемое состояние, control и решение. Две темы заранее отклонены именно за вложенный intent, а восемь внутренних leads — за недостаточную people-first ценность. Эта страница не утверждает массовость сбоя, не обещает результат обновления и не заменяет тест конкретного приложения. Операционный паспорт T20-12 начинается в состоянии «короткие wait-races заканчиваются, но await-graph продолжает удерживать завершённые waiting tasks через вечный future». Единственное разрешённое действие в test-ветке: в новом event loop многократно гонять ready future против одного never-resolving future, после каждого wait снимать размер awaited_by через доступный introspection path. Наблюдение записывается как «iteration × done/pending split × waiting task state × awaited_by size × retained objects × loop warnings», а не как свободный комментарий. Затем тот же оператор обязан выполнить опровергающую ветку «gather с явной отменой обеих задач и wait, где оба futures завершаются». Статус passed разрешён только когда после каждой итерации pending future не удерживает закончившийся waiter, а controls завершаются без pending-task warnings. Если control не проходит, это broken fixture; если нужного runtime компонента нет, это blocked environment; если данные неполны, это incomplete, но не passed. Для отката предусмотрено действие: отменить never-resolving future, собрать все tasks и закрыть loop только после нулевого pending count. В тикет попадают только loop implementation, число итераций, done/pending counts, await-graph sizes, gc control и warnings. Такой паспорт позволяет другому человеку повторить именно эту границу gh-152569, не копируя production state и не подменяя проверку соседней темой.
Материал подготовлен редакцией VOne с помощью ИИ по открытым официальным и первичным источникам; факты, даты и ссылки перепроверены. Реальные пользовательские данные не использовались.
Источники и проверка
- Python 3.14.7 release проверено 2026-08-29
- Python 3.14.7 changelog проверено 2026-08-29
- CPython issue #152569 проверено 2026-08-29
Информация актуальна на дату публикации. Правила сервисов, приложений и сетей могут меняться.