#988·pingora

Report actual listener addresses after binding

Author: torinndCreated Sep 1, 2026Updated Sep 1, 2026

What is the problem your feature solves, or the need it fulfills?

Pingora accepts port 0 in a listening-service configuration, but callers cannot learn the assigned port after moving the service into Server.

A full-server test must therefore use a fixed port or reserve one with a temporary socket. Fixed ports collide when tests run concurrently; closing the temporary socket before Pingora starts leaves a race in which another process can claim the port.

Describe the solution you'd like

Expose the addresses of a listening service after Pingora binds them:

let mut bound_addresses = service.watch_bound_addresses();
server.add_service(service);

let addresses = bound_addresses.wait_for(Option::is_some).await?;

The draft uses a watch channel. Its value changes from None to the bound TCP or Unix-domain addresses after all listeners bind, before accept loops start and before dependent services are notified that the service is ready. The channel closes without a value if listener startup fails. A callback or one-shot receiver would also satisfy the use case.

Describe alternatives you've considered

  • Accept a pre-bound listener. This gives the caller the address, but moves fd ownership outside Pingora and complicates graceful transfer.
  • Reserve a port with a temporary socket, close it, and ask Pingora to bind the same port (race-y semantics, seems bad)
  • Expose addresses from Listeners::build. The built listeners already know their addresses, but normal applications do not call this method; listening services call it inside Server startup.

Additional context

I have a draft (report-bound-listeners) that I'll open as a PR.