Reduce departure latency from 30min worst-case to 6min

Watchdog timeout and departure debounce were both 900s — stacked,
worst-case VACANT alert was 30 minutes after leaving. With active ARP
scanning every 30s we can confirm absence quickly, so both timers drop
to 180s. Override via NET_ALERTER_WATCHDOG_TIMEOUT and
NET_ALERTER_DEPARTURE_DEBOUNCE env vars.
This commit is contained in:
Cobra
2026-04-15 14:50:19 -04:00
parent 44c8e87959
commit d8c742cea6
+7 -6
View File
@@ -83,7 +83,8 @@ _churn_tracker = {} # {mac: [timestamps of departure events]}
_churn_lock = threading.Lock() _churn_lock = threading.Lock()
CHURN_THRESHOLD = 3 # cycles in window before suppression CHURN_THRESHOLD = 3 # cycles in window before suppression
CHURN_WINDOW_SEC = 1800 # 30 minutes CHURN_WINDOW_SEC = 1800 # 30 minutes
WATCHDOG_TIMEOUT_SEC = int(os.getenv("NET_ALERTER_WATCHDOG_TIMEOUT", "900")) WATCHDOG_TIMEOUT_SEC = int(os.getenv("NET_ALERTER_WATCHDOG_TIMEOUT", "180"))
DEPARTURE_DEBOUNCE_SEC = int(os.getenv("NET_ALERTER_DEPARTURE_DEBOUNCE", "180"))
# Mobile device OUI prefixes for personal device detection # Mobile device OUI prefixes for personal device detection
MOBILE_DEVICE_OUIS = { MOBILE_DEVICE_OUIS = {
@@ -1142,8 +1143,8 @@ def on_arrival(mac: str, ip: str, hostname: str = "") -> None:
def on_departure(mac: str) -> None: def on_departure(mac: str) -> None:
""" """
Handle device departure with 15-minute debounce. Handle device departure with debounce.
Only sends alert if device still gone after 15 min. Only sends alert if device still gone after DEPARTURE_DEBOUNCE_SEC.
""" """
with known_lock: with known_lock:
if mac not in known_devices: if mac not in known_devices:
@@ -1175,7 +1176,7 @@ def on_departure(mac: str) -> None:
known_devices[mac]['departing'] = True known_devices[mac]['departing'] = True
known_devices[mac]['depart_initiated'] = time.time() known_devices[mac]['depart_initiated'] = time.time()
# Start 15-minute debounce timer # Start departure debounce timer
# Extract timer to cancel outside of lock to avoid deadlock # Extract timer to cancel outside of lock to avoid deadlock
timer_to_cancel = None timer_to_cancel = None
with departure_lock: with departure_lock:
@@ -1211,13 +1212,13 @@ def on_departure(mac: str) -> None:
logging.info(msg) logging.info(msg)
send_alert(msg) send_alert(msg)
timer = threading.Timer(900.0, send_departure_alert) # 15 min = 900 sec timer = threading.Timer(float(DEPARTURE_DEBOUNCE_SEC), send_departure_alert)
timer.daemon = True timer.daemon = True
timer.name = f'departure-debounce-{mac}' timer.name = f'departure-debounce-{mac}'
departure_timers[mac] = timer departure_timers[mac] = timer
timer.start() timer.start()
logging.debug(f"Departure debounce started for {mac}, will alert in 15 min if still gone") logging.debug(f"Departure debounce started for {mac}, will alert in {DEPARTURE_DEBOUNCE_SEC}s if still gone")
def get_primary_interface() -> str: def get_primary_interface() -> str: