client: improve healthcheck

Kim committed Oct 22, 2025 at 10:06 UTC d353f66c6320787ae57563ef82a3bdbaff050f23
3 files changed +41 -4
cmd/example_chat/main.go
+1 -1
@@ -30,7 +30,7 @@ func init() {
30 flags := rootCmd.PersistentFlags()
31 flags.StringVar(&flagServerURL, "server-url", "http://relaydns.gosuda.org", "relayserver base URL to auto-fetch multiaddrs from /health")
32 flags.IntVar(&flagPort, "port", 8091, "local chat HTTP port")
33 - flags.StringVar(&flagName, "name", "bangjang-chat", "backend display name")
33 + flags.StringVar(&flagName, "name", "example-chat", "backend display name")
34 }
35
36 func main() {
cmd/example_http_client/main.go
+1 -1
@@ -31,7 +31,7 @@ func init() {
31 flags := rootCmd.PersistentFlags()
32 flags.StringVar(&flagServerURL, "server-url", "http://relaydns.gosuda.org", "relayserver admin base URL to auto-fetch multiaddrs from /health")
33 flags.IntVar(&flagPort, "port", 8081, "local backend HTTP port")
34 - flags.StringVar(&flagName, "name", "bangjang-backend", "backend display name shown on server UI")
34 + flags.StringVar(&flagName, "name", "example-backend", "backend display name shown on server UI")
35 }
36
37 func main() {
relaydns/client.go
+39 -2
@@ -12,7 +12,9 @@ import (
12 pubsub "github.com/libp2p/go-libp2p-pubsub"
13 "github.com/libp2p/go-libp2p/core/host"
14 "github.com/libp2p/go-libp2p/core/network"
15 + "github.com/libp2p/go-libp2p/core/peer"
16 "github.com/libp2p/go-libp2p/core/protocol"
17 + ma "github.com/multiformats/go-multiaddr"
18 "github.com/rs/zerolog/log"
19 )
20
@@ -117,6 +119,19 @@ func (b *RelayClient) Start(ctx context.Context) error {
119 boot := b.resolveBootstraps()
120 if len(boot) > 0 {
121 ConnectBootstraps(ctx, b.h, boot)
122 + // If a server URL is configured, only mark healthy if actually
123 + // connected to the server peer (not just able to fetch /hosts).
124 + if b.cfg.ServerURL != "" {
125 + if addrs, err := fetchMultiaddrsFromHosts(b.cfg.ServerURL, b.cfg.HTTPTimeout); err == nil {
126 + if pid, ok := serverPeerFromAddrs(addrs); ok {
127 + if b.h.Network().Connectedness(pid) == network.Connected {
128 + b.setServerHealthy(true)
129 + } else {
130 + b.setServerHealthy(false)
131 + }
132 + }
133 + }
134 + }
135 } else {
136 log.Warn().Msg("relaydns: no bootstrap sources provided (Bootstraps/ServerURL); discovery may fail")
137 }
@@ -191,7 +206,7 @@ func (b *RelayClient) resolveBootstraps() []string {
206 b.setServerHealthy(false)
207 log.Warn().Err(err).Msgf("relaydns: fetch /hosts from %s failed", b.cfg.ServerURL)
208 } else {
194 - b.setServerHealthy(true)
209 + // Do not mark healthy yet; only after verifying libp2p connectivity
210 sortMultiaddrs(addrs, b.cfg.PreferQUIC, b.cfg.PreferLocal)
211 boot = append(boot, addrs...)
212 }
@@ -296,18 +311,40 @@ func (b *RelayClient) startRefreshLoop(ctx context.Context) {
311 log.Warn().Err(err).Msgf("refresh /hosts from %s failed", b.cfg.ServerURL)
312 continue
313 }
299 - b.setServerHealthy(true)
314 sortMultiaddrs(addrs, b.cfg.PreferQUIC, b.cfg.PreferLocal)
315 addrs = RemoveDuplicate(addrs)
316 if len(addrs) > 0 {
317 // Always attempt (re)connect; ConnectBootstraps handles dedupe and quiet logging
318 ConnectBootstraps(ctx, b.h, addrs)
319 + // Only mark healthy if actually connected to server peer
320 + if pid, ok := serverPeerFromAddrs(addrs); ok {
321 + if b.h.Network().Connectedness(pid) == network.Connected {
322 + b.setServerHealthy(true)
323 + } else {
324 + b.setServerHealthy(false)
325 + }
326 + }
327 }
328 }
329 }
330 }()
331 }
332
333 +// serverPeerFromAddrs extracts the first peer.ID found in the provided
334 +// multiaddrs. The server advertises its own addrs including /p2p/<peer>.
335 +func serverPeerFromAddrs(addrs []string) (peer.ID, bool) {
336 + for _, s := range addrs {
337 + m, err := ma.NewMultiaddr(s)
338 + if err != nil {
339 + continue
340 + }
341 + if ai, err := peer.AddrInfoFromP2pAddr(m); err == nil {
342 + return ai.ID, true
343 + }
344 + }
345 + return "", false
346 +}
347 +
348 // ServerStatus returns a human-friendly status regarding connection to ServerURL.
349 // If no ServerURL is configured, returns "N/A".
350 func (b *RelayClient) ServerStatus() string {