geektutu/7days-golang · error

rpc discovery: no available servers

Error message

rpc discovery: no available servers

What it means

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.

Source

Thrown at gee-rpc/day6-load-balance/xclient/discovery.go:55

func (d *MultiServersDiscovery) Refresh() error {
	return nil
}

// Update the servers of discovery dynamically if needed
func (d *MultiServersDiscovery) Update(servers []string) error {
	d.mu.Lock()
	defer d.mu.Unlock()
	d.servers = servers
	return nil
}

// Get a server according to mode
func (d *MultiServersDiscovery) Get(mode SelectMode) (string, error) {
	d.mu.Lock()
	defer d.mu.Unlock()
	n := len(d.servers)
	if n == 0 {
		return "", errors.New("rpc discovery: no available servers")
	}
	switch mode {
	case RandomSelect:
		return d.servers[d.r.Intn(n)], nil
	case RoundRobinSelect:
		s := d.servers[d.index%n] // servers could be updated, so mode n to ensure safety
		d.index = (d.index + 1) % n
		return s, nil
	default:
		return "", errors.New("rpc discovery: not supported select mode")
	}
}

// returns all servers in discovery
func (d *MultiServersDiscovery) GetAll() ([]string, error) {
	d.mu.RLock()
	defer d.mu.RUnlock()
	// return a copy of d.servers

View on GitHub (pinned to cf36443821)

Solutions

  1. Ensure at least one server address is passed to NewMultiServersDiscovery or registered in the registry before creating the client.
  2. Guard calls: check len(discovery.GetAll()) > 0 before dialing, and retry after discovery refresh.
  3. Start the target servers so the registry has instances to report.

Example fix

// before
d := xclient.NewMultiServersDiscovery(nil)
xc := xclient.NewXDClient(d, xclient.RandomSelect)
// after
d := xclient.NewMultiServersDiscovery([]string{"tcp@127.0.0.1:9001", "tcp@127.0.0.1:9002"})
xc := xclient.NewXDClient(d, xclient.RandomSelect)
Defensive patterns

Strategy: fallback

Validate before calling

servers, _ := d.GetAll()
if len(servers) == 0 {
    // skip selection, fall back to direct address or retry after refresh
}

Try / catch

addr, err := d.Get(mode)
if err != nil && err.Error() == "rpc discovery: no available servers" {
    time.Sleep(500 * time.Millisecond) // allow discovery refresh
    addr, err = d.Get(mode)
}

Prevention

When it happens

Trigger: Creating MultiServersDiscovery with an empty address list, or the server list being emptied by Remove()/Update() before the first Get(), then calling Get(RandomSelect|RoundRobinSelect) via xclient.

Common situations: Registry returned no instances for a service (nothing registered yet), config file with an empty servers array, all peers removed during failure handling, or a race where discovery refreshes an empty list while requests are in flight.

Related errors


AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03). Data as JSON: /api/errors/cdd05a870d2fff0e. Report an issue: GitHub.