diff --git a/engine/resources.go b/engine/resources.go index c9d9ba542..f7bd08952 100644 --- a/engine/resources.go +++ b/engine/resources.go @@ -20,7 +20,9 @@ package engine import ( "fmt" + "maps" "runtime" + "slices" "sort" "sync" "time" @@ -676,13 +678,17 @@ func (rS *ResourceService) matchingResourcesForEvent(tnt string, ev *utils.CGREv return } } - rs = make(Resources, 0, len(rIDs)) - for resName := range rIDs { + + // Lock items in sorted order to prevent AB-BA deadlock. + itemIDs := slices.Sorted(maps.Keys(rIDs)) + + rs = make(Resources, 0, len(itemIDs)) + for _, id := range itemIDs { lkPrflID := guardian.Guardian.GuardIDs("", config.CgrConfig().GeneralCfg().LockingTimeout, - resourceProfileLockKey(tnt, resName)) + resourceProfileLockKey(tnt, id)) var rPrf *ResourceProfile - if rPrf, err = rS.dm.GetResourceProfile(tnt, resName, + if rPrf, err = rS.dm.GetResourceProfile(tnt, id, true, true, utils.NonTransactional); err != nil { guardian.Guardian.UnguardIDs(lkPrflID) if err == utils.ErrNotFound { diff --git a/engine/stats.go b/engine/stats.go index e1a677e1f..24ec878e1 100644 --- a/engine/stats.go +++ b/engine/stats.go @@ -20,7 +20,9 @@ package engine import ( "fmt" + "maps" "runtime" + "slices" "sync" "time" @@ -174,13 +176,17 @@ func (sS *StatService) matchingStatQueuesForEvent(tnt string, statsIDs []string, return } } - sqs = make(StatQueues, 0, len(sqIDs)) - for sqID := range sqIDs { + + // Lock items in sorted order to prevent AB-BA deadlock. + itemIDs := slices.Sorted(maps.Keys(sqIDs)) + + sqs = make(StatQueues, 0, len(itemIDs)) + for _, id := range itemIDs { lkPrflID := guardian.Guardian.GuardIDs("", config.CgrConfig().GeneralCfg().LockingTimeout, - statQueueProfileLockKey(tnt, sqID)) + statQueueProfileLockKey(tnt, id)) var sqPrfl *StatQueueProfile - if sqPrfl, err = sS.dm.GetStatQueueProfile(tnt, sqID, true, true, utils.NonTransactional); err != nil { + if sqPrfl, err = sS.dm.GetStatQueueProfile(tnt, id, true, true, utils.NonTransactional); err != nil { guardian.Guardian.UnguardIDs(lkPrflID) if err == utils.ErrNotFound { err = nil diff --git a/engine/thresholds.go b/engine/thresholds.go index f6c5b493d..c084c3230 100644 --- a/engine/thresholds.go +++ b/engine/thresholds.go @@ -20,13 +20,13 @@ package engine import ( "fmt" + "maps" "runtime" + "slices" "sort" "sync" "time" - "slices" - "github.com/cgrates/birpc/context" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/guardian" @@ -472,13 +472,17 @@ func (tS *ThresholdService) matchingThresholdsForEvent(tnt string, args *utils.C return nil, err } } - ts = make(Thresholds, 0, len(tIDs)) - for tID := range tIDs { + + // Lock items in sorted order to prevent AB-BA deadlock. + itemIDs := slices.Sorted(maps.Keys(tIDs)) + + ts = make(Thresholds, 0, len(itemIDs)) + for _, id := range itemIDs { lkPrflID := guardian.Guardian.GuardIDs("", config.CgrConfig().GeneralCfg().LockingTimeout, - thresholdProfileLockKey(tnt, tID)) + thresholdProfileLockKey(tnt, id)) var tPrfl *ThresholdProfile - if tPrfl, err = tS.dm.GetThresholdProfile(tnt, tID, true, true, utils.NonTransactional); err != nil { + if tPrfl, err = tS.dm.GetThresholdProfile(tnt, id, true, true, utils.NonTransactional); err != nil { guardian.Guardian.UnguardIDs(lkPrflID) if err == utils.ErrNotFound { err = nil