Skip to content

Commit b4b3a0b

Browse files
committed
Revert "fix: hot-swap modem driver when modem_type changes in settings (#164)"
This reverts commit f381028.
1 parent 2763819 commit b4b3a0b

File tree

2 files changed

+2
-190
lines changed

2 files changed

+2
-190
lines changed

app/main.py

Lines changed: 2 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,6 @@ def run_web(port):
4646
serve(web.app, host="0.0.0.0", port=port, threads=4, _quiet=True)
4747

4848

49-
def _get_modem_config_key(config_mgr):
50-
"""Return modem config tuple for driver hot-swap change detection."""
51-
return (
52-
config_mgr.get("modem_type", "fritzbox"),
53-
config_mgr.get("modem_url", ""),
54-
config_mgr.get("modem_user", ""),
55-
config_mgr.get("modem_password", ""),
56-
)
57-
58-
5949
def polling_loop(config_mgr, storage, stop_event):
6050
"""Flat orchestrator: tick every second, let each collector decide when to poll."""
6151
config = config_mgr.get_all()
@@ -120,13 +110,6 @@ def polling_loop(config_mgr, storage, stop_event):
120110
web.init_collector(modem_collector)
121111
web.init_collectors(collectors)
122112

123-
# Track modem config for driver hot-swap detection
124-
modem_config_key = (
125-
_get_modem_config_key(config_mgr)
126-
if modem_collector and modem_collector.name == "modem"
127-
else None
128-
)
129-
130113
log.info(
131114
"Collectors: %s",
132115
", ".join(
@@ -146,43 +129,10 @@ def _run_collector(collector):
146129
finally:
147130
collector._collect_lock.release()
148131

149-
executor = ThreadPoolExecutor(
132+
with ThreadPoolExecutor(
150133
max_workers=len(collectors), thread_name_prefix="collector"
151-
)
152-
try:
134+
) as executor:
153135
while not stop_event.is_set():
154-
# ── Driver hot-swap: detect modem config change ──
155-
if modem_config_key is not None and modem_collector:
156-
new_key = _get_modem_config_key(config_mgr)
157-
if new_key != modem_config_key:
158-
log.info(
159-
"Modem config changed (%s -> %s), hot-swapping driver",
160-
modem_config_key[0], new_key[0],
161-
)
162-
from .collectors.modem import ModemCollector
163-
from .drivers import driver_registry
164-
new_driver = driver_registry.load_driver(*new_key)
165-
new_modem = ModemCollector(
166-
driver=new_driver,
167-
analyzer_fn=analyzer.analyze,
168-
event_detector=event_detector,
169-
storage=storage,
170-
mqtt_pub=mqtt_pub,
171-
web=web,
172-
poll_interval=config_mgr.get("poll_interval", 900),
173-
notifier=notifier,
174-
)
175-
collectors = [
176-
new_modem if c is modem_collector else c
177-
for c in collectors
178-
]
179-
modem_collector = new_modem
180-
web.init_collector(new_modem)
181-
web.init_collectors(collectors)
182-
web.reset_modem_state()
183-
modem_config_key = new_key
184-
log.info("Driver hot-swapped to %s", new_key[0])
185-
186136
futures = {}
187137
for collector in collectors:
188138
if stop_event.is_set():
@@ -196,8 +146,6 @@ def _run_collector(collector):
196146

197147
try:
198148
for future in as_completed(futures, timeout=120):
199-
if stop_event.is_set():
200-
break
201149
collector = futures[future]
202150
try:
203151
_, result = future.result()
@@ -220,8 +168,6 @@ def _run_collector(collector):
220168
future.cancel()
221169

222170
stop_event.wait(1)
223-
finally:
224-
executor.shutdown(wait=False, cancel_futures=True)
225171

226172
# Cleanup MQTT
227173
if mqtt_pub:

tests/test_collectors.py

Lines changed: 0 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,137 +1175,3 @@ def test_orchestrator_stops_on_event(self, mock_web, mock_load):
11751175

11761176
polling_loop(config_mgr, storage, stop)
11771177
# If we get here without hanging, the test passes
1178-
1179-
@patch("app.drivers.driver_registry.load_driver")
1180-
@patch("app.main.web")
1181-
def test_driver_hot_swap_on_modem_type_change(self, mock_web, mock_load):
1182-
"""Polling loop should hot-swap the modem driver when modem_type changes."""
1183-
import threading
1184-
from app.main import polling_loop
1185-
1186-
mock_driver = MagicMock()
1187-
mock_driver.get_device_info.return_value = {"model": "Test", "sw_version": "1.0"}
1188-
mock_driver.get_connection_info.return_value = {}
1189-
mock_driver.get_docsis_data.return_value = {}
1190-
mock_load.return_value = mock_driver
1191-
1192-
config_mgr = self._make_config_mgr()
1193-
storage = MagicMock()
1194-
stop = threading.Event()
1195-
1196-
call_count = [0]
1197-
original_wait = stop.wait
1198-
1199-
def change_modem_after_first_tick(timeout=None):
1200-
call_count[0] += 1
1201-
if call_count[0] == 1:
1202-
# After first tick, change modem_type in config
1203-
config_mgr.get_all.return_value["modem_type"] = "tc4400"
1204-
config_mgr.get.side_effect = lambda k, d=None: {
1205-
"modem_type": "tc4400",
1206-
"modem_url": "http://fritz.box",
1207-
"modem_user": "admin",
1208-
"modem_password": "pass",
1209-
"poll_interval": 900,
1210-
}.get(k, d)
1211-
return original_wait(0)
1212-
elif call_count[0] >= 3:
1213-
stop.set()
1214-
return True
1215-
return original_wait(0)
1216-
1217-
stop.wait = change_modem_after_first_tick
1218-
1219-
polling_loop(config_mgr, storage, stop)
1220-
1221-
# load_driver should have been called at least twice:
1222-
# once for initial setup, once for hot-swap
1223-
assert mock_load.call_count >= 2
1224-
# Second call should use the new modem type
1225-
second_call = mock_load.call_args_list[1]
1226-
assert second_call[0][0] == "tc4400"
1227-
# Web state should have been reset for the swap
1228-
mock_web.reset_modem_state.assert_called()
1229-
mock_web.init_collector.assert_called()
1230-
1231-
@patch("app.drivers.driver_registry.load_driver")
1232-
@patch("app.main.web")
1233-
def test_driver_hot_swap_on_url_change(self, mock_web, mock_load):
1234-
"""Hot-swap should trigger when modem URL changes, not just type."""
1235-
import threading
1236-
from app.main import polling_loop
1237-
1238-
mock_driver = MagicMock()
1239-
mock_driver.get_device_info.return_value = {"model": "Test", "sw_version": "1.0"}
1240-
mock_driver.get_connection_info.return_value = {}
1241-
mock_driver.get_docsis_data.return_value = {}
1242-
mock_load.return_value = mock_driver
1243-
1244-
config_mgr = self._make_config_mgr()
1245-
storage = MagicMock()
1246-
stop = threading.Event()
1247-
1248-
call_count = [0]
1249-
original_wait = stop.wait
1250-
1251-
def change_url_after_first_tick(timeout=None):
1252-
call_count[0] += 1
1253-
if call_count[0] == 1:
1254-
# Change URL but keep same modem_type
1255-
config_mgr.get.side_effect = lambda k, d=None: {
1256-
"modem_type": "fritzbox",
1257-
"modem_url": "http://192.168.100.1",
1258-
"modem_user": "admin",
1259-
"modem_password": "pass",
1260-
"poll_interval": 900,
1261-
}.get(k, d)
1262-
return original_wait(0)
1263-
elif call_count[0] >= 3:
1264-
stop.set()
1265-
return True
1266-
return original_wait(0)
1267-
1268-
stop.wait = change_url_after_first_tick
1269-
1270-
polling_loop(config_mgr, storage, stop)
1271-
1272-
# load_driver called twice: initial + hot-swap for URL change
1273-
assert mock_load.call_count >= 2
1274-
second_call = mock_load.call_args_list[1]
1275-
assert second_call[0][1] == "http://192.168.100.1"
1276-
1277-
@patch("app.drivers.driver_registry.load_driver")
1278-
@patch("app.main.web")
1279-
def test_no_hot_swap_when_config_unchanged(self, mock_web, mock_load):
1280-
"""No hot-swap should occur when modem config hasn't changed."""
1281-
import threading
1282-
from app.main import polling_loop
1283-
1284-
mock_driver = MagicMock()
1285-
mock_driver.get_device_info.return_value = {"model": "Test", "sw_version": "1.0"}
1286-
mock_driver.get_connection_info.return_value = {}
1287-
mock_driver.get_docsis_data.return_value = {}
1288-
mock_load.return_value = mock_driver
1289-
1290-
config_mgr = self._make_config_mgr()
1291-
storage = MagicMock()
1292-
stop = threading.Event()
1293-
1294-
call_count = [0]
1295-
original_wait = stop.wait
1296-
1297-
def stop_after_ticks(timeout=None):
1298-
call_count[0] += 1
1299-
if call_count[0] >= 3:
1300-
stop.set()
1301-
return True
1302-
return original_wait(0)
1303-
1304-
stop.wait = stop_after_ticks
1305-
1306-
polling_loop(config_mgr, storage, stop)
1307-
1308-
# load_driver should only be called once (initial setup)
1309-
assert mock_load.call_count == 1
1310-
# reset_modem_state should NOT have been called (no swap)
1311-
mock_web.reset_modem_state.assert_not_called()

0 commit comments

Comments
 (0)