|
@@ -652,7 +652,6 @@ func (s *ClientService) bulkAdjustInboundClients(
|
|
|
}
|
|
}
|
|
|
return res
|
|
return res
|
|
|
}
|
|
}
|
|
|
- prevSettings := oldInbound.Settings
|
|
|
|
|
oldInbound.Settings = string(newSettings)
|
|
oldInbound.Settings = string(newSettings)
|
|
|
|
|
|
|
|
// A flow change rewrites the user's xray config, which the lightweight
|
|
// A flow change rewrites the user's xray config, which the lightweight
|
|
@@ -662,45 +661,6 @@ func (s *ClientService) bulkAdjustInboundClients(
|
|
|
res.needRestart = true
|
|
res.needRestart = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if oldInbound.NodeID != nil {
|
|
|
|
|
- rt, push, _, perr := inboundSvc.nodePushPlan(oldInbound)
|
|
|
|
|
- if perr != nil {
|
|
|
|
|
- for email := range foundEmails {
|
|
|
|
|
- res.perEmailSkipped[email] = perr.Error()
|
|
|
|
|
- delete(foundEmails, email)
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- if flowChanged {
|
|
|
|
|
- push = false
|
|
|
|
|
- }
|
|
|
|
|
- // Large batches collapse into one reconcile push rather than M updates.
|
|
|
|
|
- if push && len(foundEmails) > nodeBulkPushThreshold {
|
|
|
|
|
- push = false
|
|
|
|
|
- }
|
|
|
|
|
- if push {
|
|
|
|
|
- pushFailed := false
|
|
|
|
|
- for email := range foundEmails {
|
|
|
|
|
- entry := plan[email]
|
|
|
|
|
- updated := *entry.record.ToClient()
|
|
|
|
|
- if entry.applyExpiry {
|
|
|
|
|
- updated.ExpiryTime = entry.newExpiry
|
|
|
|
|
- }
|
|
|
|
|
- if entry.applyTotal {
|
|
|
|
|
- updated.TotalGB = entry.newTotal
|
|
|
|
|
- }
|
|
|
|
|
- updated.UpdatedAt = nowMs
|
|
|
|
|
- if err1 := rt.UpdateUser(context.Background(), oldInbound, email, updated); err1 != nil {
|
|
|
|
|
- logger.Warning("Error in updating client on", rt.Name(), ":", err1)
|
|
|
|
|
- pushFailed = true
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if !pushFailed {
|
|
|
|
|
- advancePushedInbound(rt, prevSettings, oldInbound)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// Serialize against the traffic poll to avoid the cross-transaction
|
|
// Serialize against the traffic poll to avoid the cross-transaction
|
|
|
// lock-order deadlock on inbounds/client_records (runSerializedTx).
|
|
// lock-order deadlock on inbounds/client_records (runSerializedTx).
|
|
|
txErr := runSerializedTx(func(tx *gorm.DB) error {
|
|
txErr := runSerializedTx(func(tx *gorm.DB) error {
|
|
@@ -725,6 +685,26 @@ func (s *ClientService) bulkAdjustInboundClients(
|
|
|
res.perEmailSkipped[email] = txErr.Error()
|
|
res.perEmailSkipped[email] = txErr.Error()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ } else if oldInbound.NodeID != nil && !flowChanged && len(foundEmails) <= nodeBulkPushThreshold {
|
|
|
|
|
+ rt, push, _, perr := inboundSvc.nodePushPlan(oldInbound)
|
|
|
|
|
+ if perr != nil {
|
|
|
|
|
+ logger.Warning("BulkAdjust: node runtime lookup after commit failed:", perr)
|
|
|
|
|
+ } else if push {
|
|
|
|
|
+ for email := range foundEmails {
|
|
|
|
|
+ entry := plan[email]
|
|
|
|
|
+ updated := *entry.record.ToClient()
|
|
|
|
|
+ if entry.applyExpiry {
|
|
|
|
|
+ updated.ExpiryTime = entry.newExpiry
|
|
|
|
|
+ }
|
|
|
|
|
+ if entry.applyTotal {
|
|
|
|
|
+ updated.TotalGB = entry.newTotal
|
|
|
|
|
+ }
|
|
|
|
|
+ updated.UpdatedAt = nowMs
|
|
|
|
|
+ if err1 := rt.UpdateUser(context.Background(), oldInbound, email, updated); err1 != nil {
|
|
|
|
|
+ logger.Warning("Error in updating client on", rt.Name(), ":", err1)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return res
|
|
return res
|
|
@@ -980,7 +960,6 @@ func (s *ClientService) bulkDelInboundClients(
|
|
|
}
|
|
}
|
|
|
return res
|
|
return res
|
|
|
}
|
|
}
|
|
|
- prevSettings := oldInbound.Settings
|
|
|
|
|
oldInbound.Settings = string(newSettings)
|
|
oldInbound.Settings = string(newSettings)
|
|
|
|
|
|
|
|
foundList := make([]string, 0, len(foundEmails))
|
|
foundList := make([]string, 0, len(foundEmails))
|
|
@@ -1048,7 +1027,31 @@ func (s *ClientService) bulkDelInboundClients(
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if oldInbound.NodeID == nil {
|
|
|
|
|
|
|
+ // Serialize against the traffic poll to avoid the cross-transaction
|
|
|
|
|
+ // lock-order deadlock on inbounds/client_records (runSerializedTx).
|
|
|
|
|
+ txErr := runSerializedTx(func(tx *gorm.DB) error {
|
|
|
|
|
+ if err := tx.Save(oldInbound).Error; err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ finalClients, err := inboundSvc.GetClients(oldInbound)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := s.SyncInbound(tx, inboundId, finalClients); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if oldInbound.NodeID != nil {
|
|
|
|
|
+ return (&NodeService{}).MarkNodeDirtyTx(tx, *oldInbound.NodeID)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+ })
|
|
|
|
|
+ if txErr != nil {
|
|
|
|
|
+ for email := range foundEmails {
|
|
|
|
|
+ if _, skip := res.perEmailSkipped[email]; !skip {
|
|
|
|
|
+ res.perEmailSkipped[email] = txErr.Error()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if oldInbound.NodeID == nil {
|
|
|
rt, rterr := inboundSvc.runtimeFor(oldInbound)
|
|
rt, rterr := inboundSvc.runtimeFor(oldInbound)
|
|
|
if rterr != nil {
|
|
if rterr != nil {
|
|
|
res.needRestart = true
|
|
res.needRestart = true
|
|
@@ -1068,62 +1071,19 @@ func (s *ClientService) bulkDelInboundClients(
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- } else {
|
|
|
|
|
|
|
+ } else if len(foundEmails) <= nodeBulkPushThreshold {
|
|
|
rt, push, _, perr := inboundSvc.nodePushPlan(oldInbound)
|
|
rt, push, _, perr := inboundSvc.nodePushPlan(oldInbound)
|
|
|
if perr != nil {
|
|
if perr != nil {
|
|
|
|
|
+ logger.Warning("BulkDelete: node runtime lookup after commit failed:", perr)
|
|
|
|
|
+ } else if push {
|
|
|
for email := range foundEmails {
|
|
for email := range foundEmails {
|
|
|
- res.perEmailSkipped[email] = perr.Error()
|
|
|
|
|
- delete(foundEmails, email)
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- // Large batches collapse into one reconcile push rather than M deletes.
|
|
|
|
|
- if push && len(foundEmails) > nodeBulkPushThreshold {
|
|
|
|
|
- push = false
|
|
|
|
|
- }
|
|
|
|
|
- if push {
|
|
|
|
|
- // bulkDelInboundClients only runs for full client deletion
|
|
|
|
|
- // (BulkDelete), so the node must drop its client record too,
|
|
|
|
|
- // not just detach from this inbound (#5797).
|
|
|
|
|
- pushFailed := false
|
|
|
|
|
- for email := range foundEmails {
|
|
|
|
|
- if err1 := rt.DeleteClient(context.Background(), email); err1 != nil {
|
|
|
|
|
- logger.Warning("Error in deleting client on", rt.Name(), ":", err1)
|
|
|
|
|
- pushFailed = true
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if !pushFailed {
|
|
|
|
|
- advancePushedInbound(rt, prevSettings, oldInbound)
|
|
|
|
|
|
|
+ if err1 := rt.DeleteClient(context.Background(), email); err1 != nil {
|
|
|
|
|
+ logger.Warning("Error in deleting client on", rt.Name(), ":", err1)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Serialize against the traffic poll to avoid the cross-transaction
|
|
|
|
|
- // lock-order deadlock on inbounds/client_records (runSerializedTx).
|
|
|
|
|
- txErr := runSerializedTx(func(tx *gorm.DB) error {
|
|
|
|
|
- if err := tx.Save(oldInbound).Error; err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
- finalClients, err := inboundSvc.GetClients(oldInbound)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
- if err := s.SyncInbound(tx, inboundId, finalClients); err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
- if oldInbound.NodeID != nil {
|
|
|
|
|
- return (&NodeService{}).MarkNodeDirtyTx(tx, *oldInbound.NodeID)
|
|
|
|
|
- }
|
|
|
|
|
- return nil
|
|
|
|
|
- })
|
|
|
|
|
- if txErr != nil {
|
|
|
|
|
- for email := range foundEmails {
|
|
|
|
|
- if _, skip := res.perEmailSkipped[email]; !skip {
|
|
|
|
|
- res.perEmailSkipped[email] = txErr.Error()
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
return res
|
|
return res
|
|
|
}
|
|
}
|
|
|
|
|
|