Skip to content

Commit d3645e4

Browse files
Yaminyamclaudefregataa
authored
chore: drop the now-unused aiodns/pycares dependencies (main only) (#12979)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Sanghun Lee <sanghun@lablup.com>
1 parent ed28f87 commit d3645e4

7 files changed

Lines changed: 20 additions & 63 deletions

File tree

changes/12979.fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a native memory and file-descriptor leak in all long-running components making aiohttp client requests: since aiodns 3.2, aiohttp defaulted to the aiodns/pycares resolver, and every ephemeral client session leaked a c-ares channel (native heap growth plus one `/dev/urandom` fd per channel, ~85k fds on 16-day-old agents). aiodns/pycares are removed so aiohttp uses its threaded resolver, and the boot-time self-IP lookup now uses the stdlib `loop.getaddrinfo()`.

python.lock

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,6 @@ wheels = [
5959
{ url = "https://files.pythonhosted.org/packages/c6/29/80a0a91bd35b46bf31dc53a620780ee7c5b48b4dab7e60fdc4979641846a/aiodataloader-0.4.3-py3-none-any.whl", hash = "sha256:f2d57675e4c7a5cf7efc4c42697d307b951e1a9f40c22df3531a4b9cb7758229", size = 11029, upload-time = "2025-11-29T10:14:09.417Z" },
6060
]
6161

62-
[[package]]
63-
name = "aiodns"
64-
version = "3.2.0"
65-
source = { registry = "https://pypi.org/simple/" }
66-
dependencies = [
67-
{ name = "pycares" },
68-
]
69-
sdist = { url = "https://files.pythonhosted.org/packages/e7/84/41a6a2765abc124563f5380e76b9b24118977729e25a84112f8dfb2b33dc/aiodns-3.2.0.tar.gz", hash = "sha256:62869b23409349c21b072883ec8998316b234c9a9e36675756e8e317e8768f72", size = 7823, upload-time = "2024-03-31T11:27:30.639Z" }
70-
wheels = [
71-
{ url = "https://files.pythonhosted.org/packages/15/14/13c65b1bd59f7e707e0cc0964fbab45c003f90292ed267d159eeeeaa2224/aiodns-3.2.0-py3-none-any.whl", hash = "sha256:e443c0c27b07da3174a109fd9e736d69058d808f144d3c9d56dbd1776964c5f5", size = 5735, upload-time = "2024-03-31T11:27:28.615Z" },
72-
]
73-
7462
[[package]]
7563
name = "aiodocker"
7664
version = "0.27.0"
@@ -1833,7 +1821,6 @@ source = { virtual = "." }
18331821
dependencies = [
18341822
{ name = "aioboto3" },
18351823
{ name = "aiodataloader" },
1836-
{ name = "aiodns" },
18371824
{ name = "aiodocker" },
18381825
{ name = "aiofiles" },
18391826
{ name = "aiohttp" },
@@ -1903,7 +1890,6 @@ dependencies = [
19031890
{ name = "pexpect" },
19041891
{ name = "prometheus-client" },
19051892
{ name = "psutil" },
1906-
{ name = "pycares" },
19071893
{ name = "pycryptodome" },
19081894
{ name = "pydantic", extra = ["email"] },
19091895
{ name = "pyhumps" },
@@ -1965,7 +1951,6 @@ dependencies = [
19651951
requires-dist = [
19661952
{ name = "aioboto3", specifier = "~=15.0.0" },
19671953
{ name = "aiodataloader", specifier = "~=0.4.2" },
1968-
{ name = "aiodns", specifier = "==3.2" },
19691954
{ name = "aiodocker", specifier = "==0.27.0" },
19701955
{ name = "aiofiles", specifier = "~=24.1.0" },
19711956
{ name = "aiohttp", specifier = "~=3.13.3" },
@@ -2035,7 +2020,6 @@ requires-dist = [
20352020
{ name = "pexpect", specifier = "~=4.8" },
20362021
{ name = "prometheus-client", specifier = "~=0.21.1" },
20372022
{ name = "psutil", specifier = "~=7.0" },
2038-
{ name = "pycares", specifier = "~=4.11.0" },
20392023
{ name = "pycryptodome", specifier = ">=3.20.0" },
20402024
{ name = "pydantic", extras = ["email"], specifier = "~=2.11.3" },
20412025
{ name = "pyhumps", specifier = "~=3.8.0" },
@@ -2270,30 +2254,6 @@ wheels = [
22702254
{ url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" },
22712255
]
22722256

2273-
[[package]]
2274-
name = "pycares"
2275-
version = "4.11.0"
2276-
source = { registry = "https://pypi.org/simple/" }
2277-
dependencies = [
2278-
{ name = "cffi" },
2279-
]
2280-
sdist = { url = "https://files.pythonhosted.org/packages/8d/ad/9d1e96486d2eb5a2672c4d9a2dd372d015b8d7a332c6ac2722c4c8e6bbbf/pycares-4.11.0.tar.gz", hash = "sha256:c863d9003ca0ce7df26429007859afd2a621d3276ed9fef154a9123db9252557", size = 654473, upload-time = "2025-09-09T15:18:21.849Z" }
2281-
wheels = [
2282-
{ url = "https://files.pythonhosted.org/packages/dc/a9/62fea7ad72ac1fed2ac9dd8e9a7379b7eb0288bf2b3ea5731642c3a6f7de/pycares-4.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c296ab94d1974f8d2f76c499755a9ce31ffd4986e8898ef19b90e32525f7d84", size = 145909, upload-time = "2025-09-09T15:17:10.491Z" },
2283-
{ url = "https://files.pythonhosted.org/packages/f4/ac/0317d6d0d3bd7599c53b8f1db09ad04260647d2f6842018e322584791fd5/pycares-4.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e0fcd3a8bac57a0987d9b09953ba0f8703eb9dca7c77f7051d8c2ed001185be8", size = 141974, upload-time = "2025-09-09T15:17:11.634Z" },
2284-
{ url = "https://files.pythonhosted.org/packages/63/11/731b565ae1e81c43dac247a248ee204628186f6df97c9927bd06c62237f8/pycares-4.11.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:bac55842047567ddae177fb8189b89a60633ac956d5d37260f7f71b517fd8b87", size = 637796, upload-time = "2025-09-09T15:17:12.815Z" },
2285-
{ url = "https://files.pythonhosted.org/packages/f5/30/a2631fe2ffaa85475cdbff7df1d9376bc0b2a6ae77ca55d53233c937a5da/pycares-4.11.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:4da2e805ed8c789b9444ef4053f6ef8040cd13b0c1ca6d3c4fe6f9369c458cb4", size = 687734, upload-time = "2025-09-09T15:17:14.015Z" },
2286-
{ url = "https://files.pythonhosted.org/packages/a9/b7/b3a5f99d4ab776662e71d5a56e8f6ea10741230ff988d1f502a8d429236b/pycares-4.11.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:ea785d1f232b42b325578f0c8a2fa348192e182cc84a1e862896076a4a2ba2a7", size = 678320, upload-time = "2025-09-09T15:17:15.442Z" },
2287-
{ url = "https://files.pythonhosted.org/packages/ea/77/a00d962b90432993afbf3bd05da8fe42117e0d9037cd7fd428dc41094d7b/pycares-4.11.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:aa160dc9e785212c49c12bb891e242c949758b99542946cc8e2098ef391f93b0", size = 641012, upload-time = "2025-09-09T15:17:16.728Z" },
2288-
{ url = "https://files.pythonhosted.org/packages/c6/fb/9266979ba59d37deee1fd74452b2ae32a7395acafe1bee510ac023c6c9a5/pycares-4.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7830709c23bbc43fbaefbb3dde57bdd295dc86732504b9d2e65044df8fd5e9fb", size = 622363, upload-time = "2025-09-09T15:17:17.835Z" },
2289-
{ url = "https://files.pythonhosted.org/packages/91/c2/16dbc3dc33781a3c79cbdd76dd1cda808d98ba078d9a63a725d6a1fad181/pycares-4.11.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ef1ab7abbd238bb2dbbe871c3ea39f5a7fc63547c015820c1e24d0d494a1689", size = 670294, upload-time = "2025-09-09T15:17:19.214Z" },
2290-
{ url = "https://files.pythonhosted.org/packages/ff/75/f003905e55298a6dd5e0673a2dc11e31518a5141393b925dc05fcaba9fb4/pycares-4.11.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:a4060d8556c908660512d42df1f4a874e4e91b81f79e3a9090afedc7690ea5ba", size = 652973, upload-time = "2025-09-09T15:17:20.388Z" },
2291-
{ url = "https://files.pythonhosted.org/packages/55/2a/eafb235c371979e11f8998d686cbaa91df6a84a34ffe4d997dfe57c45445/pycares-4.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a98fac4a3d4f780817016b6f00a8a2c2f41df5d25dfa8e5b1aa0d783645a6566", size = 629235, upload-time = "2025-09-09T15:17:21.92Z" },
2292-
{ url = "https://files.pythonhosted.org/packages/05/99/60f19eb1c8eb898882dd8875ea51ad0aac3aff5780b27247969e637cc26a/pycares-4.11.0-cp313-cp313-win32.whl", hash = "sha256:faa8321bc2a366189dcf87b3823e030edf5ac97a6b9a7fc99f1926c4bf8ef28e", size = 118918, upload-time = "2025-09-09T15:17:23.327Z" },
2293-
{ url = "https://files.pythonhosted.org/packages/2a/14/bc89ad7225cba73068688397de09d7cad657d67b93641c14e5e18b88e685/pycares-4.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:6f74b1d944a50fa12c5006fd10b45e1a45da0c5d15570919ce48be88e428264c", size = 144556, upload-time = "2025-09-09T15:17:24.341Z" },
2294-
{ url = "https://files.pythonhosted.org/packages/af/88/4309576bd74b5e6fc1f39b9bc5e4b578df2cadb16bdc026ac0cc15663763/pycares-4.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:4b6f7581793d8bb3014028b8397f6f80b99db8842da58f4409839c29b16397ad", size = 115692, upload-time = "2025-09-09T15:17:25.637Z" },
2295-
]
2296-
22972257
[[package]]
22982258
name = "pycparser"
22992259
version = "3.0"

python.lock.metadata

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
"SQLAlchemy[postgresql_asyncpg]~=2.0.45",
1111
"aioboto3~=15.0.0",
1212
"aiodataloader~=0.4.2",
13-
"aiodns==3.2",
1413
"aiodocker==0.27.0",
1514
"aiofiles~=24.1.0",
1615
"aiohttp_cors~=0.8.1",
@@ -79,7 +78,6 @@
7978
"pexpect~=4.8",
8079
"prometheus-client~=0.21.1",
8180
"psutil~=7.0",
82-
"pycares~=4.11.0",
8381
"pycryptodome>=3.20.0",
8482
"pydantic[email]~=2.11.3",
8583
"pyhumps~=3.8.0",

requirements.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ aiohttp_cors~=0.8.1
77
aiohttp_remotes~=1.3.0
88
aiohttp_jinja2~=1.6
99
aiohttp_sse>=2.2
10-
aiodns==3.2
1110
aiomonitor~=0.7.0
1211
aioresponses>=0.7.3
1312
aiosqlite~=0.21.0
@@ -63,7 +62,6 @@ opentelemetry-instrumentation-logging~=0.60b0
6362
pexpect~=4.8
6463
prometheus-client~=0.21.1
6564
psutil~=7.0
66-
pycares~=4.11.0
6765
pycryptodome>=3.20.0
6866
habana-pyhlml~=1.22.1.6
6967
pyhumps~=3.8.0

src/ai/backend/common/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ python_sources(
44
dependencies=[
55
":resources",
66
"stubs/trafaret:stubs",
7-
"//:reqs#pycares", # aiodns runtime dependency - pin version explicitly
87
],
98
)
109

src/ai/backend/common/identity.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
from pathlib import Path, PosixPath
1818
from typing import Any
1919

20-
import aiodns
2120
import aiohttp
2221
import ifaddr
2322
import psutil
@@ -395,11 +394,16 @@ async def _get_instance_ip(_subnet_hint: BaseIPNetwork[Any] | None = None) -> st
395394
)
396395
try:
397396
myself = socket.gethostname()
398-
resolver = aiodns.DNSResolver()
399-
result = await resolver.gethostbyname(myself, socket.AF_INET)
400-
address: str = result.addresses[0]
397+
loop = asyncio.get_running_loop()
398+
addrinfo = await loop.getaddrinfo(
399+
myself,
400+
None,
401+
family=socket.AF_INET,
402+
type=socket.SOCK_STREAM,
403+
)
404+
address: str = addrinfo[0][4][0]
401405
return address
402-
except aiodns.error.DNSError:
406+
except (socket.gaierror, IndexError):
403407
return "127.0.0.1"
404408

405409
async def _get_instance_type() -> str:

tests/unit/common/test_identity.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from typing import Any
1010
from unittest.mock import AsyncMock, MagicMock, patch
1111

12-
import aiodns
1312
import aiohttp
1413
import pytest
1514
from aioresponses import aioresponses
@@ -159,28 +158,26 @@ async def test_get_instance_ip(provider: str | None) -> None:
159158
ret = await ai.backend.common.identity.get_instance_ip(None)
160159
assert ret == random_ip
161160
elif provider is None:
162-
mocked_ares_host_result = MagicMock()
163-
mocked_ares_host_result.addresses = ["10.1.2.3"]
164-
mocked_resolver = MagicMock()
165161

166-
async def coro_return_mocked_result(*args: Any) -> MagicMock:
167-
return mocked_ares_host_result
162+
async def coro_return_addrinfo(*args: Any, **kwargs: Any) -> list[Any]:
163+
return [(socket.AF_INET, socket.SOCK_STREAM, 6, "", ("10.1.2.3", 0))]
168164

169-
mocked_resolver.gethostbyname = coro_return_mocked_result
165+
mocked_loop = MagicMock()
166+
mocked_loop.getaddrinfo = coro_return_addrinfo
170167
with (
171-
patch("aiodns.DNSResolver", return_value=mocked_resolver),
168+
patch("asyncio.get_running_loop", return_value=mocked_loop),
172169
patch("socket.gethostname", return_value="myname"),
173170
):
174171
ret = await ai.backend.common.identity.get_instance_ip(None)
175172
assert ret == "10.1.2.3"
176173

177-
async def coro_raise_error(*args: Any) -> None:
178-
raise aiodns.error.DNSError("domain not found")
174+
async def coro_raise_error(*args: Any, **kwargs: Any) -> None:
175+
raise socket.gaierror(socket.EAI_NONAME, "domain not found")
179176

180-
mocked_resolver = MagicMock()
181-
mocked_resolver.gethostbyname = coro_raise_error
177+
mocked_loop = MagicMock()
178+
mocked_loop.getaddrinfo = coro_raise_error
182179
with (
183-
patch("aiodns.DNSResolver", return_value=mocked_resolver),
180+
patch("asyncio.get_running_loop", return_value=mocked_loop),
184181
patch("socket.gethostname", return_value="myname"),
185182
):
186183
ret = await ai.backend.common.identity.get_instance_ip(None)

0 commit comments

Comments
 (0)