Repository: learningequality/kolibri

Issue:
Continual re-initialization of zeroconf every 5 seconds
https://www.notion.so/learningequality/BUG-Continual-re-initialization-of-zeroconf-every-5-seconds-9d6917de73024f00b106b50251eff2be

The log files on my Windows machine show "New addresses detected since zeroconf was initialized, updating now" messages every 5 seconds. I added additional logging to the following code:

```
logger.info(
    "New addresses detected since zeroconf was initialized, updating now"
)
logger.info("Old list: " + str(self.broadcast.addresses))
logger.info("New list: " + str(set(get_all_addresses())))
```

which shows that the zeroconf-internal list has stripped out the link-local addresses and so the comparison is never true:

```
INFO 2021-12-07 11:07:22,701 kolibri.utils.server New addresses detected since zeroconf was initialized, updating now
INFO 2021-12-07 11:07:22,702 kolibri.utils.server Old list: {'172.24.32.1', '192.168.137.1', '6.5.75.243', '172.22.48.1', '127.0.0.1'}
INFO 2021-12-07 11:07:22,709 kolibri.utils.server New list: {'172.24.32.1', '169.254.148.11', '169.254.117.77', '169.254.203.37', '192.168.137.1', '10.0.85.2', '169.254.181.43', '6.5.75.243', '127.0.0.1', '169.254.173.0', '169.254.226.233', '172.22.48.1', '169.254.22.56', '169.254.14.241'}
```

Proposed solution:

- Update get_all_addresses to exclude link-local addresses
- Use a local cache of the address list on the ZeroConfPlugin as an additional less brittle way of detecting changes
Continual re-initialization of zeroconf every 5 seconds
https://www.notion.so/learningequality/BUG-Continual-re-initialization-of-zeroconf-every-5-seconds-9d6917de73024f00b106b50251eff2be

The log files on my Windows machine show "New addresses detected since zeroconf was initialized, updating now" messages every 5 seconds. I added additional logging to the following code:

```
logger.info(
    "New addresses detected since zeroconf was initialized, updating now"
)
logger.info("Old list: " + str(self.broadcast.addresses))
logger.info("New list: " + str(set(get_all_addresses())))
```

which shows that the zeroconf-internal list has stripped out the link-local addresses and so the comparison is never true:

```
INFO 2021-12-07 11:07:22,701 kolibri.utils.server New addresses detected since zeroconf was initialized, updating now
INFO 2021-12-07 11:07:22,702 kolibri.utils.server Old list: {'172.24.32.1', '192.168.137.1', '6.5.75.243', '172.22.48.1', '127.0.0.1'}
INFO 2021-12-07 11:07:22,709 kolibri.utils.server New list: {'172.24.32.1', '169.254.148.11', '169.254.117.77', '169.254.203.37', '192.168.137.1', '10.0.85.2', '169.254.181.43', '6.5.75.243', '127.0.0.1', '169.254.173.0', '169.254.226.233', '172.22.48.1', '169.254.22.56', '169.254.14.241'}
```

Proposed solution:

- Update get_all_addresses to exclude link-local addresses
- Use a local cache of the address list on the ZeroConfPlugin as an additional less brittle way of detecting changes


Discussion:
Seems likely that this is causing global issues on the windows installer.
Seems likely that this is causing global issues on the windows installer.

Resolving patch:
diff --git a/kolibri/core/discovery/utils/network/broadcast.py b/kolibri/core/discovery/utils/network/broadcast.py
--- a/kolibri/core/discovery/utils/network/broadcast.py
+++ b/kolibri/core/discovery/utils/network/broadcast.py
@@ -336,7 +336,7 @@ def start_broadcast(self):
         # register our instance so we start broadcasting
         self.register()
 
-        # manually add our service browser to Zeroconf so its automatically cleaned up on close
+        # manually add our service browser to Zeroconf so it's automatically cleaned up on close
         self.zeroconf.browsers["bus"] = ServiceBrowser(
             self.zeroconf, SERVICE_TYPE, handlers=[self.events.publish_zeroconf_change]
         )
diff --git a/kolibri/utils/server.py b/kolibri/utils/server.py
--- a/kolibri/utils/server.py
+++ b/kolibri/utils/server.py
@@ -305,6 +305,9 @@ def SERVING(self, port):
         else:
             self.broadcast.update_broadcast(instance=instance)
 
+        # cache the list of addresses active right now, so we can detect changes
+        self.addresses = get_all_addresses()
+
     def UPDATE_ZEROCONF(self):
         self.SERVING(self.port)
 
@@ -316,17 +319,16 @@ def STOP(self):
             self.broadcast = None
 
     def run(self):
-        # If the current addresses that zeroconf is listening on does not
-        # match the current set of all addresses for this device, then
-        # we should reinitialize zeroconf, the listener, and the broadcast
-        # kolibri service.
-        if self.broadcast is not None and self.broadcast.addresses != set(
-            get_all_addresses()
-        ):
+        # If set of addresses that were present at the last time zeroconf updated its broadcast list
+        # don't match the current set of all addresses for this device, then we should reinitialize
+        # zeroconf, the listener, and the broadcast kolibri service.
+        current_addresses = get_all_addresses()
+        if self.addresses != current_addresses:
             logger.info(
-                "New addresses detected since zeroconf was initialized, updating now"
+                "List of local addresses has changed since zeroconf was last initialized, updating now"
             )
             self.broadcast.update_broadcast(interfaces=InterfaceChoice.All)
+            self.addresses = current_addresses
 
 
 status_map = {


Test patch: