Two Krill servers on the same LAN, started at different times, may not discover each other until one is restarted. The server that started first never lists the later-starting server as a peer.
ServerBeaconSupervisor.startBeaconProcess() sent a single startup beacon (beaconSender.sendSignal()) and then only listened, reacting to incoming beacons from new peers. If Server A started first and its single best-effort UDP multicast beacon was dropped — or arrived before Server B’s socket had joined the multicast group — Server A never heard Server B. Because neither side ever re-announced after the one-shot startup, the silence was permanent until a restart emitted a fresh beacon. The ServerBeaconSupervisor KDoc described beacons as “periodic” but the implementation was one-shot. Same root cause as the client-side bug fixed in docs/lessons/2026-06-18-beacon-reprobe-stuck-search.md.
startReannounceLoop() to server/src/jvmMain/kotlin/krill/zone/server/io/beacon/ServerBeaconSupervisor.kt — a coroutine that calls beaconSender.sendSignal() every REANNOUNCE_INTERVAL_MS (5 s). The loop starts before the listener job so the first re-announce fires even if the listener has trouble.ServerBeaconSender already rate-limits via BEACON_MIN_INTERVAL_MS (1 s), so the 5 s loop cadence is an upper bound on actual wire sends — no flooding risk.server/src/jvmTest/kotlin/krill/zone/server/io/beacon/ServerBeaconSupervisorReannounceTest.kt using virtual time and a fake BeaconSender — no filesystem reads, no real sockets, no wall-clock assertions.BeaconSupervisor KDoc describes “periodic” behavior, verify the implementation actually has a loop, not just a one-shot send. The interface comment already said “periodic” — keep the KDoc and the code in sync.runTest { advanceTimeBy(N * interval) }) — wall-clock assertions on multicast behavior are inherently flaky.