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]

Reply via email to