mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-12 06:10:58 +00:00
perf(clients): scale-audit remaining client/inbound endpoints to 200k
Drive every client/inbound/group endpoint at 100k-200k clients on PostgreSQL and fix the latent issues found in previously-unbenchmarked paths: - enrichClientStats: chunk the email IN lookup (was an unchunked bind that crashed past 65535 clients without traffic rows, taking down GetInbounds/GetInboundDetail/GetAllInbounds) - GetOnlineClients: add the missing nil-process guard its siblings already have, so ListPaged no longer panics before xray starts - GetClientTrafficByEmail: read UUID/subId from the indexed clients table instead of parsing the inbound's full settings JSON (439ms to ~1.5ms, flat in N) - BulkResetTraffic: replace the per-email serialized loop with one chunked bulk UPDATE in a single transaction - DelDepleted: delegate to the already-batched BulkDelete instead of deleting each depleted client one by one Adds a postgres-gated full endpoint sweep plus an A/B benchmark, and SQLite correctness tests for the changed methods.
This commit is contained in:
+37
-8
@@ -83,8 +83,17 @@ func (s *InboundService) enrichClientStats(db *gorm.DB, inbounds []*model.Inboun
|
||||
emails = append(emails, e)
|
||||
}
|
||||
var extra []xray.ClientTraffic
|
||||
if err := db.Model(xray.ClientTraffic{}).Where("email IN ?", emails).Find(&extra).Error; err != nil {
|
||||
logger.Warning("enrichClientStats:", err)
|
||||
var loadErr error
|
||||
for _, batch := range chunkStrings(emails, sqlInChunk) {
|
||||
var page []xray.ClientTraffic
|
||||
if err := db.Model(xray.ClientTraffic{}).Where("email IN ?", batch).Find(&page).Error; err != nil {
|
||||
loadErr = err
|
||||
break
|
||||
}
|
||||
extra = append(extra, page...)
|
||||
}
|
||||
if loadErr != nil {
|
||||
logger.Warning("enrichClientStats:", loadErr)
|
||||
} else {
|
||||
byEmail := make(map[string]xray.ClientTraffic, len(extra))
|
||||
for _, st := range extra {
|
||||
@@ -3048,16 +3057,33 @@ func (s *InboundService) GetInboundsTrafficSummary() ([]InboundTrafficSummary, e
|
||||
}
|
||||
|
||||
func (s *InboundService) GetClientTrafficByEmail(email string) (traffic *xray.ClientTraffic, err error) {
|
||||
// Prefer retrieving along with client to reflect actual enabled state from inbound settings
|
||||
t, client, err := s.GetClientByEmail(email)
|
||||
db := database.GetDB()
|
||||
var traffics []*xray.ClientTraffic
|
||||
if err := db.Model(xray.ClientTraffic{}).Where("email = ?", email).Find(&traffics).Error; err != nil {
|
||||
logger.Warningf("Error retrieving ClientTraffic with email %s: %v", email, err)
|
||||
return nil, err
|
||||
}
|
||||
if len(traffics) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
t := traffics[0]
|
||||
|
||||
if rec, rErr := s.clientService.GetRecordByEmail(db, email); rErr == nil && rec != nil {
|
||||
c := rec.ToClient()
|
||||
t.UUID = c.ID
|
||||
t.SubId = c.SubID
|
||||
return t, nil
|
||||
}
|
||||
|
||||
t2, client, err := s.GetClientByEmail(email)
|
||||
if err != nil {
|
||||
logger.Warningf("Error retrieving ClientTraffic with email %s: %v", email, err)
|
||||
return nil, err
|
||||
}
|
||||
if t != nil && client != nil {
|
||||
t.UUID = client.ID
|
||||
t.SubId = client.SubID
|
||||
return t, nil
|
||||
if t2 != nil && client != nil {
|
||||
t2.UUID = client.ID
|
||||
t2.SubId = client.SubID
|
||||
return t2, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -3386,6 +3412,9 @@ func (s *InboundService) MigrateDB() {
|
||||
}
|
||||
|
||||
func (s *InboundService) GetOnlineClients() []string {
|
||||
if p == nil {
|
||||
return []string{}
|
||||
}
|
||||
return p.GetOnlineClients()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user