Title: Socket leak when opening, and closing sockets · Issue #1589 · python-zeroconf/python-zeroconf · GitHub
Open Graph Title: Socket leak when opening, and closing sockets · Issue #1589 · python-zeroconf/python-zeroconf
X Title: Socket leak when opening, and closing sockets · Issue #1589 · python-zeroconf/python-zeroconf
Description: Even though #171 and the subsequent fix in PR #188/270 addressed one class of socket leaks, we’re still seeing file-descriptor leaks when creating and tearing down Zeroconf instances in rapid succession (e.g. one per “cycle”). Over time,...
Open Graph Description: Even though #171 and the subsequent fix in PR #188/270 addressed one class of socket leaks, we’re still seeing file-descriptor leaks when creating and tearing down Zeroconf instances in rapid succe...
X Description: Even though #171 and the subsequent fix in PR #188/270 addressed one class of socket leaks, we’re still seeing file-descriptor leaks when creating and tearing down Zeroconf instances in rapid succe...
Opengraph URL: https://github.com/python-zeroconf/python-zeroconf/issues/1589
X: @github
Domain: patch-diff.githubusercontent.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Socket leak when opening, and closing sockets","articleBody":"Even though https://github.com/jstasiak/python-zeroconf/issues/171 and the subsequent fix in PR #188/270 addressed one class of socket leaks, we’re still seeing file-descriptor leaks when creating and tearing down Zeroconf instances in rapid succession (e.g. one per “cycle”). Over time, the process exhausts its FD limit with errors like OSError: [Errno 24] Too many open files.\nWhat’s happening\n\nPersistent sockets remain open\nEvery time Zeroconf(interfaces=[…]) is called, it creates a set of listening and responding sockets. Although those sockets are closed (via .close()) when the instance is torn down, some underlying file descriptors remain open in the OS.\n\nLingering asyncio selectors and threads\nThe library spins up an asyncio event loop per instance. Even after .close(), we observe threads (in selector_events.py and _core.py) that never fully tear down, holding onto their self-pipes or sockets.\n\nifaddr adapter enumeration leak\nIn our environment, each new Zeroconf triggers an ifaddr.get_adapters() call—which under certain Linux distributions seems to leave open netlink sockets or file handles that are never garbage-collected.\n\n\nReproduction steps\n\nWrite a simple loop that does:\n\n```python\nfrom zeroconf import Zeroconf\nimport time\nimport os\n\n# Run a tight loop creating \u0026 closing Zeroconf instances\nfor i in range(1, 1001):\n zc = Zeroconf(interfaces=['127.0.0.1'])\n zc.close()\n if i % 100 == 0:\n print(f\"Iteration {i}\")\n time.sleep(0.1) # give the OS a moment\n\ndef fd_count():\n return len(os.listdir(f\"/proc/{os.getpid()}/fd\"))\n\nfor i in range(1,1001):\n zc = Zeroconf(interfaces=['127.0.0.1'])\n zc.close()\n if i % 100 == 0:\n print(f\"Iteration {i}, open-fds: {fd_count()}\")\n```\n\n\nExpected behavior\n\nAfter zc.close(), all sockets, event loops, and threads associated with that Zeroconf instance should be fully torn down, and the OS file descriptor count should return to its prior level.\n\n\nEnvironment\n\npython-zeroconf version: ≥ 0.28.0 (includes the fixes from PR #188/270)\nOS: Ubuntu 24.04, Linux kernel 6.x\nPython: 3.12\n\n\nSuggested investigation areas\n\n- Verify that every internal selector and asyncio loop is explicitly closed and that its underlying sockets/pipes are closed too.\n- Audit ifaddr.get_adapters() and its use of netlink sockets—ensure that any sockets opened for adapter enumeration are closed.\n- Add a regression test that repeatedly constructs and closes Zeroconf objects and asserts that FD count remains constant.\n\n\n\nI'm trying to write a unidirectional mDNS reflector solution, it works flawlessly if I start, and then stop the main reflector script rather than simply closing the sockets, but this requires a wrapper script to then handle this with added complexity along with added noise \u0026 advertisements appearing, then disappearing when the reflector script exits.\n\n\nUnfortunately, I don't know enough to patch this, and implement a fix effectively, I've been fault finding with the use of AI to be able to get this write up where it is so there could be some incorrect information, but running the code above I can re-produce the issue on different systems.\n\nIf you need any help testing, I'd be happy to assist where I can","author":{"url":"https://github.com/brayden-b-LA","@type":"Person","name":"brayden-b-LA"},"datePublished":"2025-05-25T09:42:52.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/1589/python-zeroconf/issues/1589"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:e84cfed3-2ffd-4fd3-e3aa-8e76bd2d6853 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | AFBA:63CEC:18102C5:2090E83:6972B30D |
| html-safe-nonce | b6ba650d60c2b0cc75df2f6804ed458abd7082b0d8f2ab1d5d08c5f84b973624 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJBRkJBOjYzQ0VDOjE4MTAyQzU6MjA5MEU4Mzo2OTcyQjMwRCIsInZpc2l0b3JfaWQiOiI3ODQ4NjQzODcxNTAyNDE0NjA1IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | a8e89182c1b332532817626adc47a8f537240dfd2c9a8f155501eb097985ba5f |
| hovercard-subject-tag | issue:3089177103 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python-zeroconf/python-zeroconf/1589/issue_layout |
| twitter:image | https://opengraph.githubassets.com/2dc48458cdec499d751fecc55aaaaa9eb2b526875993bd5d139bbd9569ce17d8/python-zeroconf/python-zeroconf/issues/1589 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/2dc48458cdec499d751fecc55aaaaa9eb2b526875993bd5d139bbd9569ce17d8/python-zeroconf/python-zeroconf/issues/1589 |
| og:image:alt | Even though #171 and the subsequent fix in PR #188/270 addressed one class of socket leaks, we’re still seeing file-descriptor leaks when creating and tearing down Zeroconf instances in rapid succe... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | brayden-b-LA |
| hostname | github.com |
| expected-hostname | github.com |
| None | 51c0d0848f5569c6fa2198e9d69bd5f8f94a83c9fa3659e40728e7732afab130 |
| turbo-cache-control | no-preview |
| go-import | github.com/python-zeroconf/python-zeroconf git https://github.com/python-zeroconf/python-zeroconf.git |
| octolytics-dimension-user_id | 120192235 |
| octolytics-dimension-user_login | python-zeroconf |
| octolytics-dimension-repository_id | 21548731 |
| octolytics-dimension-repository_nwo | python-zeroconf/python-zeroconf |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 21548731 |
| octolytics-dimension-repository_network_root_nwo | python-zeroconf/python-zeroconf |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 10c5e2f2307495b2750073db87e9a5d3356a924f |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width