[object Object]

← back to Exo

Remove change-detection checks from info gatherer monitors (#1283)

44453c4c8b61d32ff9ff6f7953f241c1e30299df · 2026-01-26 04:23:22 -0800 · Alex Cheema

## Summary
- When a node times out, its info gets cleared from state. The monitor
functions only sent data when something changed, leaving no mechanism to
re-populate this info after a timeout.
- Removes change-detection checks from `_monitor_misc`,
`_monitor_system_profiler_thunderbolt_data`, `_watch_system_info`, and
`_monitor_thunderbolt_bridge_status` so data is sent periodically
regardless of whether it changed.

## Test plan
- [ ] Verify type checker passes: `uv run basedpyright`
- [ ] Verify linter passes: `uv run ruff check`
- [ ] Verify tests pass: `uv run pytest`
- [ ] Manually test that node info is re-populated after a timeout by
observing cluster behavior

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

Files touched

Diff

commit 44453c4c8b61d32ff9ff6f7953f241c1e30299df
Author: Alex Cheema <41707476+AlexCheema@users.noreply.github.com>
Date:   Mon Jan 26 04:23:22 2026 -0800

    Remove change-detection checks from info gatherer monitors (#1283)
    
    ## Summary
    - When a node times out, its info gets cleared from state. The monitor
    functions only sent data when something changed, leaving no mechanism to
    re-populate this info after a timeout.
    - Removes change-detection checks from `_monitor_misc`,
    `_monitor_system_profiler_thunderbolt_data`, `_watch_system_info`, and
    `_monitor_thunderbolt_bridge_status` so data is sent periodically
    regardless of whether it changed.
    
    ## Test plan
    - [ ] Verify type checker passes: `uv run basedpyright`
    - [ ] Verify linter passes: `uv run ruff check`
    - [ ] Verify tests pass: `uv run pytest`
    - [ ] Manually test that node info is re-populated after a timeout by
    observing cluster behavior
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
---
 src/exo/utils/info_gatherer/info_gatherer.py | 21 ++++-----------------
 1 file changed, 4 insertions(+), 17 deletions(-)

diff --git a/src/exo/utils/info_gatherer/info_gatherer.py b/src/exo/utils/info_gatherer/info_gatherer.py
index 7f1d6269..0b931eda 100644
--- a/src/exo/utils/info_gatherer/info_gatherer.py
+++ b/src/exo/utils/info_gatherer/info_gatherer.py
@@ -349,13 +349,8 @@ class InfoGatherer:
     async def _monitor_misc(self):
         if self.misc_poll_interval is None:
             return
-        prev = await MiscData.gather()
-        await self.info_sender.send(prev)
         while True:
-            curr = await MiscData.gather()
-            if prev != curr:
-                prev = curr
-                await self.info_sender.send(curr)
+            await self.info_sender.send(await MiscData.gather())
             await anyio.sleep(self.misc_poll_interval)
 
     async def _monitor_system_profiler_thunderbolt_data(self):
@@ -365,15 +360,12 @@ class InfoGatherer:
         if iface_map is None:
             return
 
-        old_idents = []
         while True:
             data = await ThunderboltConnectivity.gather()
             assert data is not None
 
             idents = [it for i in data if (it := i.ident(iface_map)) is not None]
-            if idents != old_idents:
-                await self.info_sender.send(MacThunderboltIdentifiers(idents=idents))
-            old_idents = idents
+            await self.info_sender.send(MacThunderboltIdentifiers(idents=idents))
 
             conns = [it for i in data if (it := i.conn()) is not None]
             await self.info_sender.send(MacThunderboltConnections(conns=conns))
@@ -398,22 +390,17 @@ class InfoGatherer:
     async def _watch_system_info(self):
         if self.interface_watcher_interval is None:
             return
-        old_nics = []
         while True:
             nics = await get_network_interfaces()
-            if nics != old_nics:
-                old_nics = nics
-                await self.info_sender.send(NodeNetworkInterfaces(ifaces=nics))
+            await self.info_sender.send(NodeNetworkInterfaces(ifaces=nics))
             await anyio.sleep(self.interface_watcher_interval)
 
     async def _monitor_thunderbolt_bridge_status(self):
         if self.thunderbolt_bridge_poll_interval is None:
             return
-        prev: ThunderboltBridgeInfo | None = None
         while True:
             curr = await ThunderboltBridgeInfo.gather()
-            if curr is not None and prev != curr:
-                prev = curr
+            if curr is not None:
                 await self.info_sender.send(curr)
             await anyio.sleep(self.thunderbolt_bridge_poll_interval)
 

← 1290e8ed dashboard: fix prettier-svelte rebuilding on every file chan  ·  back to Exo  ·  Fix download system for upstream file changes (#1290) 0e30b083 →