[Bug] [Zeta] Dynamic REST port is not written back to HttpConfig, so cluster fan-out addresses the wrong node
- Dominant language
- Java
- Stars
- 9.7k
- Forks
- 2.4k
- Avg merge
- 3d 9h
- Merged PRs (30d)
- 204
Description
### Search before asking
- [X] I had searched in the [issues](https://github.com/apache/seatunnel/issues?q=is%3Aissue+label%3A%22bug%22) and found no similar issues.
### What happened
When `seatunnel.engine.http.enable-dynamic-port` is `true` and the configured port is already in use, `JettyService` picks a free port and binds to it, but the chosen port is never written back to `HttpConfig`. `HttpConfig.getPort()` keeps returning the *configured* port rather than the *bound* port.
Every cluster-wide REST fan-out resolves a peer's HTTP port through `GetNodeHttpPortOperation`, which simply reads that stale value:
```java
// GetNodeHttpPortOperation#run
SeaTunnelServer service = getService();
response = service.getSeaTunnelConfig().getEngineConfig().getHttpConfig().getPort();
```
So on a node that took a dynamic port, peers keep addressing the configured port instead. The most visible consequence is in `LogService#allLogNameList`, which iterates every member and issues an HTTP GET to each member's reported port:
```java
String url = "http://" + host + ":" + nodeHttpPort + contextPath;
...
final String nodeId = host + ":" + nodeHttpPort;
```
On a single-host cluster where node A binds the configured port and node B falls back to a dynamic one, node B reports node A's port. Therefore:
- `GET /logs` enumerates node A twice and **never lists node B's local log files**;
- both entries carry an identical `nodeId` (`host:`);
- the returned `href` links for node B's files point at node A.
`LoggerLevelService` resolves peer ports the same way, so `GET /loggers?scope=cluster` is affected as well.
### Why existing tests do not catch it
`RestApiIT` already builds exactly this topology, and the stale value silently degrades it:
- node1 does `setPort(8080)` and starts first, binding 8080;
- node2 sets no port, so it inherits `port: 8080` from `seatunnel-e2e/.../test/resources/seatunnel.yaml`, and sets `setEnableDynamicPort(true)`. It therefore always falls back to another port;
- `beforeClass` then records `ports.put(node2HzPort, node2Config...getHttpConfig().getPort())`, which is the stale `8080`.
`ports` maps the Hazelcast member port to the HTTP port. REST v1 assertions use the key (the member port) and are unaffected, but every REST v2 assertion uses the value — so all of them address node1 on both iterations, and **node2's Jetty endpoints are never actually exercised**.
`verifyLogLink` passes for the wrong reason: node2's `href` points at node1, and node1 is the master, so the expected `Init JobMaster for Job fake_to_file` content is present.
### SeaTunnel Version
dev
### SeaTunnel Config
```conf
seatunnel:
engine:
http:
enable-http: true
port: 8080
enable-dynamic-port: true
```
Two nodes on the same host, so the second one falls back to a dynamic port.
### Running Command
```shell
curl http://:/logs
```
### Error Exception
```log
No exception is thrown; the response is silently wrong.
```
### Zeta or Flink or Spark Version
Zeta
### Java or Scala Version
_No response_
### Screenshots
_No response_
### Are you willing to submit PR?
- [X] Yes I am willing to submit a PR!
### Code of Conduct
- [X] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct)
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.