mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-16 05:39:54 +05:00
APIs - locking balance and action triggers when operating on them, adding reloadScheduler attribute in some methods
This commit is contained in:
@@ -71,6 +71,7 @@ type AttrRemActionTiming struct {
|
||||
Tenant string // Tenant he account belongs to
|
||||
Account string // Account name
|
||||
Direction string // Traffic direction
|
||||
ReloadScheduler bool // If set it will reload the scheduler after adding
|
||||
}
|
||||
|
||||
// Removes an ActionTimings or parts of it depending on filters being set
|
||||
@@ -83,18 +84,26 @@ func (self *ApierV1) RemActionTiming(attrs AttrRemActionTiming, reply *string) e
|
||||
return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
|
||||
}
|
||||
}
|
||||
// ToDo: lock here actionTimings
|
||||
ats, err := self.AccountDb.GetActionTimings(attrs.ActionTimingsId)
|
||||
_, err := engine.AccLock.Guard(engine.ACTION_TIMING_PREFIX+attrs.ActionTimingId, func() (float64, error) { // ToDo: Expand the scheduler to consider the locks also
|
||||
ats, err := self.AccountDb.GetActionTimings(attrs.ActionTimingsId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
} else if len(ats) == 0 {
|
||||
return 0, errors.New(utils.ERR_NOT_FOUND)
|
||||
}
|
||||
ats = engine.RemActionTiming(ats, attrs.ActionTimingId, utils.BalanceKey(attrs.Tenant, attrs.Account, attrs.Direction))
|
||||
if err := self.AccountDb.SetActionTimings(attrs.ActionTimingsId, ats); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 0, nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
} else if len(ats) == 0 {
|
||||
return errors.New(utils.ERR_NOT_FOUND)
|
||||
}
|
||||
ats = engine.RemActionTiming(ats, attrs.ActionTimingId, utils.BalanceKey(attrs.Tenant, attrs.Account, attrs.Direction))
|
||||
if err := self.AccountDb.SetActionTimings(attrs.ActionTimingsId, ats); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
if attrs.ReloadScheduler && self.Sched != nil {
|
||||
self.Sched.LoadActionTimings(self.AccountDb)
|
||||
self.Sched.Restart()
|
||||
}
|
||||
// ToDo: Unlock here actionTimings
|
||||
*reply = OK
|
||||
return nil
|
||||
}
|
||||
@@ -120,27 +129,34 @@ type AttrRemAcntActionTriggers struct {
|
||||
}
|
||||
|
||||
// Returns a list of ActionTriggers on an account
|
||||
func (self *ApierV1) RemAccountActionTriggers(attrs AttrRemAcntActionTrigger, reply *string) error {
|
||||
func (self *ApierV1) RemAccountActionTriggers(attrs AttrRemAcntActionTriggers, reply *string) error {
|
||||
if missing := utils.MissingStructFields(&attrs, []string{"Tenant", "Account", "Direction"}); len(missing) != 0 {
|
||||
return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
|
||||
}
|
||||
ub, err := self.AccountDb.GetUserBalance(utils.BalanceKey(attrs.Tenant, attrs.Account, attrs.Direction))
|
||||
balanceId := utils.BalanceKey(attrs.Tenant, attrs.Account, attrs.Direction)
|
||||
_, err := engine.AccLock.Guard(balanceId, func() (float64, error) {
|
||||
ub, err := self.AccountDb.GetUserBalance(balanceId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for idx, actr := range ub.ActionTriggers {
|
||||
if len(attrs.ActionTriggerId) != 0 && actr.Id != attrs.ActionTriggerId { // Empty actionTriggerId will match always
|
||||
continue
|
||||
}
|
||||
if len(ub.ActionTriggers) != 1 { // Remove by index
|
||||
ub.ActionTriggers[idx], ub.ActionTriggers = ub.ActionTriggers[len(ub.ActionTriggers)-1], ub.ActionTriggers[:len(ub.ActionTriggers)-1]
|
||||
} else { // For last item, simply reinit the slice
|
||||
ub.ActionTriggers = make(engine.ActionTriggerPriotityList, 0)
|
||||
}
|
||||
}
|
||||
if err := self.AccountDb.SetUserBalance(ub); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 0, nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
}
|
||||
for idx, actr := range ub.ActionTriggers {
|
||||
if len(attrs.ActionTriggerId) != 0 && actr.Id != attrs.ActionTriggerId { // Empty actionTriggerId will match always
|
||||
continue
|
||||
}
|
||||
if len(ub.ActionTriggers) != 1 { // Remove by index
|
||||
ub.ActionTriggers[idx], ub.ActionTriggers = ub.ActionTriggers[len(ub.ActionTriggers)-1], ub.ActionTriggers[:len(ub.ActionTriggers)-1]
|
||||
} else { // For last item, simply reinit the slice
|
||||
ub.ActionTriggers = make(engine.ActionTriggerPriotityList, 0)
|
||||
}
|
||||
}
|
||||
if err := self.AccountDb.SetUserBalance(ub); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
}
|
||||
*reply = OK
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -288,6 +288,7 @@ type AttrSetActionTimings struct {
|
||||
ActionTimingsId string // Profile id
|
||||
Overwrite bool // If previously defined, will be overwritten
|
||||
ActionTimings []*ApiActionTiming // Set of actions this Actions profile will perform
|
||||
ReloadScheduler bool // Enables automatic reload of the scheduler (eg: useful when adding a single action timing)
|
||||
}
|
||||
|
||||
type ApiActionTiming struct {
|
||||
@@ -342,6 +343,10 @@ func (self *ApierV1) SetActionTimings(attrs AttrSetActionTimings, reply *string)
|
||||
if err := self.AccountDb.SetActionTimings(attrs.ActionTimingsId, storeAtms); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
}
|
||||
if attrs.ReloadScheduler && self.Sched != nil {
|
||||
self.Sched.LoadActionTimings(self.AccountDb)
|
||||
self.Sched.Restart()
|
||||
}
|
||||
*reply = OK
|
||||
return nil
|
||||
}
|
||||
@@ -375,7 +380,7 @@ func (self *ApierV1) AddTriggeredAction(attr AttrAddActionTrigger, reply *string
|
||||
Executed: false,
|
||||
}
|
||||
|
||||
tag := fmt.Sprintf("%s:%s:%s", attr.Direction, attr.Tenant, attr.Account)
|
||||
tag := utils.BalanceKey(attr.Tenant, attr.Account, attr.Direction)
|
||||
_, err := engine.AccLock.Guard(tag, func() (float64, error) {
|
||||
userBalance, err := self.AccountDb.GetUserBalance(tag)
|
||||
if err != nil {
|
||||
@@ -410,7 +415,7 @@ func (self *ApierV1) AddAccount(attr AttrAddAccount, reply *string) error {
|
||||
if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Direction", "Account", "Type", "ActionTimingsId"}); len(missing) != 0 {
|
||||
return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
|
||||
}
|
||||
tag := fmt.Sprintf("%s:%s:%s", attr.Direction, attr.Tenant, attr.Account)
|
||||
tag := utils.BalanceKey(attr.Tenant, attr.Account, attr.Direction)
|
||||
ub := &engine.UserBalance{
|
||||
Id: tag,
|
||||
Type: attr.Type,
|
||||
@@ -441,7 +446,7 @@ func (self *ApierV1) AddAccount(attr AttrAddAccount, reply *string) error {
|
||||
}
|
||||
|
||||
// Process dependencies and load a specific AccountActions profile from storDb into dataDb.
|
||||
func (self *ApierV1) SetAccountActions(attrs utils.TPAccountActions, reply *string) error {
|
||||
func (self *ApierV1) LoadAccountActions(attrs utils.TPAccountActions, reply *string) error {
|
||||
if missing := utils.MissingStructFields(&attrs, []string{"TPid", "LoadId", "Tenant", "Account", "Direction"}); len(missing) != 0 {
|
||||
return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
|
||||
}
|
||||
@@ -464,14 +469,14 @@ func (self *ApierV1) SetAccountActions(attrs utils.TPAccountActions, reply *stri
|
||||
}
|
||||
|
||||
func (self *ApierV1) ReloadScheduler(input string, reply *string) error {
|
||||
if self.Sched != nil {
|
||||
self.Sched.LoadActionTimings(self.AccountDb)
|
||||
self.Sched.Restart()
|
||||
*reply = OK
|
||||
return nil
|
||||
if self.Sched == nil {
|
||||
return errors.New(utils.ERR_NOT_FOUND)
|
||||
}
|
||||
*reply = utils.ERR_NOT_FOUND
|
||||
return errors.New(utils.ERR_NOT_FOUND)
|
||||
self.Sched.LoadActionTimings(self.AccountDb)
|
||||
self.Sched.Restart()
|
||||
*reply = OK
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (self *ApierV1) ReloadCache(attrs utils.ApiReloadCache, reply *string) error {
|
||||
|
||||
@@ -754,17 +754,17 @@ func TestApierSetRatingProfile(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test here SetAccountActions
|
||||
func TestApierSetAccountActions(t *testing.T) {
|
||||
// Test here LoadAccountActions
|
||||
func TestApierLoadAccountActions(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
reply := ""
|
||||
aa1 := &utils.TPAccountActions{TPid: engine.TEST_SQL, LoadId: engine.TEST_SQL, Tenant: "cgrates.org", Account: "1001", Direction: "*out"}
|
||||
if err := rater.Call("ApierV1.SetAccountActions", aa1, &reply); err != nil {
|
||||
t.Error("Got error on ApierV1.SetAccountActions: ", err.Error())
|
||||
if err := rater.Call("ApierV1.LoadAccountActions", aa1, &reply); err != nil {
|
||||
t.Error("Got error on ApierV1.LoadAccountActions: ", err.Error())
|
||||
} else if reply != "OK" {
|
||||
t.Error("Calling ApierV1.SetAccountActions got reply: ", reply)
|
||||
t.Error("Calling ApierV1.LoadAccountActions got reply: ", reply)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user