Jackie-Jiang opened a new pull request, #19855: URL: https://github.com/apache/pinot/pull/19855
## Summary `MultiClusterIntegrationTest` and `SameTableNameMultiClusterIntegrationTest` fail in `setUp` with `RuntimeException: Failed to start http server`, caused by `BindException: Address already in use`. This is the most common Integration Test Set 2 failure: 25 of the 43 failed jobs between 2026-09-26 and 2026-10-13, all at the same line (`BaseMultiClusterIntegrationTest.java:148`). ### Root cause `startBrokerWithUnavailableCluster` probed its HTTP port with `findOpenPort(55000)`, which only checks that the port is free and then releases it. The broker binds that port only at the end of `start()`, after its connection to the deliberately unreachable ZK at `localhost:29999` times out, about 60 seconds later. 55000 is inside the Linux ephemeral range (32768–60999), and it is even, which is the parity `connect()` tries first. The two CI lanes share one runner, so an outgoing connection can take the port during that window. The other hard-coded ports either sit below the ephemeral range (30000–32002) or are bound within about a second of the probe (40000–42002), which is why only this broker failed. ### Fix - All ports come from the per-fork `ControllerTest` port range (`_nextControllerPort`, `_nextBrokerPort`, `_nextServerPort`) instead of hard-coded 30000 / 40000 / 55000 bases. CI sets that range per lane via `pinot.test.port.base`, to disjoint bands below the ephemeral range. - Brokers and servers get explicit multi-stage engine ports from the same range. Otherwise they fall back to `NetUtils.findOpenPort()` (a bind to port 0), and the broker's query runner port would hit the same 60-second window. - `tearDown` runs with `alwaysRun = true`, so a failed `setUp` no longer leaves both clusters running for the rest of the lane. Each component is stopped independently, so a half-started one doesn't prevent the rest from stopping. ### Cleanup - `ClusterConfig` is replaced by a cluster name on `ClusterComponents`, so a broker reads its remote cluster's name from the remote `ClusterComponents`. - Both broker setups share one `initBroker` helper. `_brokerWithUnavailableCluster` is a plain `BaseBrokerStarter`, and broker ports are read through `getPort()`. - The touched files were also reformatted, so the diff is larger than the logic change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
