mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-25 15:25:01 +03:00
perf(runtime): pool the local xray gRPC connection (#6916)
A client per runtime operation made a bulk delete pay a TCP and HTTP/2 handshake for every client. The local runtime now keeps one gRPC client per API port and replaces it when a core restart moves the port; the traffic poll keeps its own client, since StatsLastValues is unlocked. A pooled channel keeps grpc-go's reconnect backoff after the core restarts, so a call that fails with Unavailable drops the client and dials again, as a client per call did.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
)
|
||||
|
||||
// One pooled gRPC client serves local runtime operations; never use it for traffic stats, whose
|
||||
// unlocked StatsLastValues a second reader would corrupt, so the traffic poll keeps its own client.
|
||||
var (
|
||||
localAPIMu sync.Mutex
|
||||
localAPIPort int
|
||||
localAPIClient *xray.XrayAPI
|
||||
)
|
||||
|
||||
// localAPIForPort returns the pooled client for the API port, replacing (and closing) it when a core
|
||||
// restart moved the port; callers must not close it.
|
||||
func localAPIForPort(port int) (*xray.XrayAPI, error) {
|
||||
localAPIMu.Lock()
|
||||
defer localAPIMu.Unlock()
|
||||
|
||||
if localAPIClient != nil {
|
||||
if localAPIPort == port {
|
||||
return localAPIClient, nil
|
||||
}
|
||||
localAPIClient.Close()
|
||||
localAPIClient = nil
|
||||
}
|
||||
|
||||
api := &xray.XrayAPI{}
|
||||
if err := api.Init(port); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localAPIClient = api
|
||||
localAPIPort = port
|
||||
return api, nil
|
||||
}
|
||||
|
||||
// evictLocalAPIClient closes the pooled client so the next call dials a fresh connection, unless
|
||||
// another call already replaced the one that failed.
|
||||
func evictLocalAPIClient(api *xray.XrayAPI) {
|
||||
localAPIMu.Lock()
|
||||
defer localAPIMu.Unlock()
|
||||
|
||||
if localAPIClient != api {
|
||||
return
|
||||
}
|
||||
localAPIClient.Close()
|
||||
localAPIClient = nil
|
||||
localAPIPort = 0
|
||||
}
|
||||
Reference in New Issue
Block a user