lizining1231 opened a new pull request, #3645:
URL: https://github.com/apache/dubbo-go/pull/3645
### Description
Fixes #3640
`Server.startHttp2AndHttp3` starts HTTP/2 and HTTP/3 inside a plain
`errgroup.Group{}`, whose `Wait()` only returns after ALL goroutines finish.
When either the TCP or the UDP port is occupied, the failing side returns its
bind error while the successful side keeps listening — so `Wait()` never
returns and `Run` hangs forever, leaving the successful listener, its port and
a goroutine occupied.
The same hang reappears after a successful bind when either `Serve` exits
abnormally at runtime: the other side stays listening, and without an explicit
close `eg.Wait()` blocks forever.
### Changes
- **Pre-bind both sockets up front**: `net.Listen("tcp", s.addr)` for HTTP/2
and `net.ListenPacket("udp", s.addr)` for HTTP/3; a bind failure on either side
returns the error immediately and closes the already-bound socket — a port
conflict can no longer hang `Run`
- **TLS readiness check**: `Certificates` / `GetCertificate` /
`GetConfigForClient` (any non-empty) is required before binding, so
`ServeTLS(tcpLn, "", "")` cannot fail inside a goroutine and hang `Wait` a
second way
- **Explicit mutual close on abnormal Serve exit**: when either `Serve`
returns an error other than `http.ErrServerClosed`, close the other side
explicitly so its `Serve` call returns, then let `eg.Wait()` collect both
goroutines — no blocked goroutine, no leaked socket
- Switch the goroutines from `ListenAndServeTLS` / `ListenAndServe` to
`ServeTLS(tcpLn, "", "")` / `Serve(udpConn)` on the pre-bound sockets
- Add package-level `netListen` / `netListenPacket` function variables so
tests can inject listeners that fail after a successful bind
### Test
Add 11 regression tests in `server_lifecycle_test.go` :
| Group | Test
| Description
|
| ---------------- |
------------------------------------------------------------ |
---------------------------------------------------------------------------------------------------------------------------
|
| Occupied port | 1. `TestServer_HTTP2AndHTTP3_StartFailsOnOccupiedTCP`
| TCP port occupied → `Run` returns `address already in use` within 3s
instead of hanging |
| <br /> | 2. `TestServer_HTTP2AndHTTP3_StartFailsOnOccupiedUDP`
| UDP port occupied → symmetric, fails fast
|
| TLS without cert | 1. `TestServer_Run_HTTP2AndHTTP3_TLSWithoutCert`
| TLS config with no usable certificate → `Run` returns an explicit error
immediately |
| Serve failure | 1. `TestServer_HTTP2AndHTTP3_ServeFailsOnHTTP2Side`
| Bind succeeds, HTTP/2 `Serve` fails immediately → `Run` returns the
error and the HTTP/3 side is closed (UDP port released) |
| <br /> | 2. `TestServer_HTTP2AndHTTP3_ServeFailsOnHTTP3Side`
| Symmetric: HTTP/3 `Serve` fails → HTTP/2 side closed (TCP port released)
|
| Port released | 1. `TestServer_HTTP2AndHTTP3_StopReleasesTCPPort`
| After `Stop`, the TCP port can be bound again
|
| <br /> | 2. `TestServer_HTTP2AndHTTP3_StopReleasesUDPPort`
| After `Stop`, the UDP port can be bound again
|
| <br /> | 3.
`TestServer_HTTP2AndHTTP3_GracefulStopReleasesTCPPort` | After
`GracefulStop`, the TCP port can be bound again
|
| <br /> | 4.
`TestServer_HTTP2AndHTTP3_GracefulStopReleasesUDPPort` | After
`GracefulStop`, the UDP port can be bound again
|
| Race | 1. `TestServer_HTTP2AndHTTP3_ConcurrentStartAndStop`
| 10 concurrent start-and-stop cycles so the `Store` calls in
`startHttp2AndHttp3` overlap with the `Load` calls in `Stop` |
| <br /> | 2.
`TestServer_HTTP2AndHTTP3_ConcurrentStartAndGracefulStop` | Same overlap
through the `GracefulStop` path
|
### Validation
- TCP / UDP occupied: `Run` returns `address already in use` in \~0.00s
(before the fix it hung for 3s+ until the test timeout)
- `go test -race -count=1 -timeout=15m ./protocol/triple/triple_protocol/`
— `ok 27.290s`, no `DATA RACE`, no FAIL
### Checklist
- [x] I confirm the target branch is `develop`
- [x] Code has passed local testing
- [x] I have added tests that prove my fix is effective or that my feature
works
--
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]