{"record":{"id":"e9e6fda80178c28e","repo":"geektutu/7days-golang","slug":"rpc-discovery-no-available-servers-e9e6fd","errorCode":null,"errorMessage":"rpc discovery: no available servers","messagePattern":"rpc discovery: no available servers","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-rpc/day7-registry/xclient/discovery.go","lineNumber":55,"sourceCode":"func (d *MultiServersDiscovery) Refresh() error {\n\treturn nil\n}\n\n// Update the servers of discovery dynamically if needed\nfunc (d *MultiServersDiscovery) Update(servers []string) error {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\td.servers = servers\n\treturn nil\n}\n\n// Get a server according to mode\nfunc (d *MultiServersDiscovery) Get(mode SelectMode) (string, error) {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tn := len(d.servers)\n\tif n == 0 {\n\t\treturn \"\", errors.New(\"rpc discovery: no available servers\")\n\t}\n\tswitch mode {\n\tcase RandomSelect:\n\t\treturn d.servers[d.r.Intn(n)], nil\n\tcase RoundRobinSelect:\n\t\ts := d.servers[d.index%n] // servers could be updated, so mode n to ensure safety\n\t\td.index = (d.index + 1) % n\n\t\treturn s, nil\n\tdefault:\n\t\treturn \"\", errors.New(\"rpc discovery: not supported select mode\")\n\t}\n}\n\n// returns all servers in discovery\nfunc (d *MultiServersDiscovery) GetAll() ([]string, error) {\n\td.mu.RLock()\n\tdefer d.mu.RUnlock()\n\t// return a copy of d.servers","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-rpc/day7-registry/xclient/discovery.go#L37-L73","documentation":"Guard in MultiServersDiscovery.Get: the discovery instance's server list is empty (n == 0), so no peer can be selected under any SelectMode. It fires when Update was never called or the known set of servers shrank to nothing.","triggerScenarios":"Creating GeeDiscovery/MultiServersDiscovery with an empty servers slice, constructing a Geo-based client whose initial registry push has not arrived yet, or all servers being removed via Update and then calling Get.","commonSituations":"Registry (etcd) has no registered servers for the service; service prefix wrong so no instances are fetched; calling a client before the registry watcher populates the list; every backend deregistered after crashes.","solutions":["Register at least one server instance under the expected prefix in the registry before creating clients","Verify the registry address and service prefix match between server registration and client discovery","Wait for/watch the initial discovery update (registryWatcher) before issuing calls; add a readiness check or brief retry","Handle the error in XClient call paths by refreshing discovery (call d.Update/refreshAndReportToCache) or surfacing 'no backends' to the user"],"exampleFix":"// before\nd := xclient.NewGeeDiscovery(registry, \"@geerpc/\"+service) // no servers registered yet\nclient := xclient.NewXClient(d, xclient.RandomSelect, ...)\n// after\n// ensure servers register first, then poll for availability\nfor i := 0; i < 10; i++ {\n    if _, err := d.GetAll(); err == nil && len(servers) > 0 { break }\n    time.Sleep(500 * time.Millisecond)\n}","handlingStrategy":"retry","validationCode":"func hasServers(d *xclient.MultiServersDiscovery) bool {\n    servers, err := d.GetAll()\n    return err == nil && len(servers) > 0\n}\n// wait for the registry to populate before creating/calling the client","typeGuard":null,"tryCatchPattern":"for attempt := 0; attempt < 5; attempt++ {\n    err := xc.Call(ctx, \"Foo.Sum\", args, &reply)\n    if err == nil { break }\n    if strings.Contains(err.Error(), \"no available servers\") {\n        time.Sleep(500 * time.Millisecond) // registry may not be populated yet\n        continue\n    }\n    return err\n}","preventionTips":["Ensure backends register in etcd/registry before clients start calling","Match the registry address and service prefix exactly between server and client","Monitor registry instance counts and alert when zero servers remain","Add a readiness delay or watch-event wait before issuing the first call"],"tags":["go","rpc","service-discovery","load-balancing"],"backgroundTag":"no-servers-available","analyzedSha":"cf3644382101dc13e7fd92e8f5c66cabc51bcd3b","analyzedAt":"2026-09-03T18:31:24.087Z","contentChangedAt":"2026-09-03T18:31:24.087Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}