SMG SessionTTLMaxDelay for SessionTTL randomization

This commit is contained in:
DanB
2017-03-10 16:42:11 +01:00
parent b8964cd684
commit 0b975f7a51
7 changed files with 73 additions and 29 deletions

View File

@@ -272,8 +272,7 @@ const CGRATES_CFG_JSON = `
"min_call_duration": "0s", // only authorize calls with allowed duration higher than this
"max_call_duration": "3h", // maximum call duration a prepaid call can last
"session_ttl": "0s", // time after a session with no updates is terminated, not defined by default
//"min_session_ttl": "", // activates session_ttl randomization as minimum possible session_ttl
//"max_session_ttl": "", // used in case of session_ttl randomization as maximum possible session_ttl, unlimited if not defined
//"session_ttl_max_delay": "", // activates session_ttl randomization and limits the maximum possible delay
//"session_ttl_last_used": "", // tweak LastUsed for sessions timing-out, not defined by default
//"session_ttl_usage": "", // tweak Usage for sessions timing-out, not defined by default
"session_indexes": [], // index sessions based on these fields for GetActiveSessions API

View File

@@ -196,8 +196,7 @@ type SmGenericJsonCfg struct {
Min_call_duration *string
Max_call_duration *string
Session_ttl *string
Min_session_ttl *string
Max_session_ttl *string
Session_ttl_max_delay *string
Session_ttl_last_used *string
Session_ttl_usage *string
Session_indexes *[]string

View File

@@ -97,8 +97,7 @@ type SmGenericConfig struct {
MinCallDuration time.Duration
MaxCallDuration time.Duration
SessionTTL time.Duration
MinSessionTTL *time.Duration
MaxSessionTTL *time.Duration
SessionTTLMaxDelay *time.Duration
SessionTTLLastUsed *time.Duration
SessionTTLUsage *time.Duration
SessionIndexes utils.StringMap
@@ -156,18 +155,11 @@ func (self *SmGenericConfig) loadFromJsonCfg(jsnCfg *SmGenericJsonCfg) error {
return err
}
}
if jsnCfg.Min_session_ttl != nil {
if minSesTTL, err := utils.ParseDurationWithSecs(*jsnCfg.Min_session_ttl); err != nil {
if jsnCfg.Session_ttl_max_delay != nil {
if maxTTLDelay, err := utils.ParseDurationWithSecs(*jsnCfg.Session_ttl_max_delay); err != nil {
return err
} else {
self.MinSessionTTL = &minSesTTL
}
}
if jsnCfg.Max_session_ttl != nil {
if maxSesTTL, err := utils.ParseDurationWithSecs(*jsnCfg.Max_session_ttl); err != nil {
return err
} else {
self.MaxSessionTTL = &maxSesTTL
self.SessionTTLMaxDelay = &maxTTLDelay
}
}
if jsnCfg.Session_ttl_last_used != nil {

View File

@@ -20,6 +20,7 @@ package sessionmanager
import (
"encoding/json"
"fmt"
"math/rand"
"strconv"
"time"
@@ -185,17 +186,47 @@ func (self SMGenericEvent) GetLastUsed(fieldName string) (time.Duration, error)
}
// GetSessionTTL retrieves SessionTTL setting out of SMGenericEvent
func (self SMGenericEvent) GetSessionTTL() time.Duration {
func (self SMGenericEvent) GetSessionTTL(sesTTL time.Duration, cfgSessionTTLMaxDelay *time.Duration) time.Duration {
valIf, hasVal := self[utils.SessionTTL]
if !hasVal {
return time.Duration(0)
if hasVal {
ttlStr, converted := utils.ConvertIfaceToString(valIf)
if !converted {
utils.Logger.Warning(fmt.Sprintf("SMGenericEvent, cannot convert SessionTTL, disabling functionality for event: <%s>",
self.GetCGRID(utils.META_DEFAULT)))
return time.Duration(0)
}
var err error
if sesTTL, err = utils.ParseDurationWithSecs(ttlStr); err != nil {
utils.Logger.Warning(fmt.Sprintf("SMGenericEvent, cannot parse SessionTTL, disabling functionality for event: <%s>",
self.GetCGRID(utils.META_DEFAULT)))
return time.Duration(0)
}
}
ttlStr, converted := utils.ConvertIfaceToString(valIf)
if !converted {
return time.Duration(0)
// Variable sessionTTL
var sessionTTLMaxDelay int64
if cfgSessionTTLMaxDelay != nil {
sessionTTLMaxDelay = cfgSessionTTLMaxDelay.Nanoseconds() / 1000000 // Milliseconds precision
}
ttl, _ := utils.ParseDurationWithSecs(ttlStr)
return ttl
if sesTTLMaxDelayIf, hasVal := self[utils.SessionTTLMaxDelay]; hasVal {
maxTTLDelaxStr, converted := utils.ConvertIfaceToString(sesTTLMaxDelayIf)
if !converted {
utils.Logger.Warning(fmt.Sprintf("SMGenericEvent, cannot convert SessionTTLMaxDelay, disabling functionality for event: <%s>",
self.GetCGRID(utils.META_DEFAULT)))
return time.Duration(0)
}
if maxTTLDelay, err := utils.ParseDurationWithSecs(maxTTLDelaxStr); err != nil {
utils.Logger.Warning(fmt.Sprintf("SMGenericEvent, cannot parse SessionTTLMaxDelay, disabling functionality for event: <%s>",
self.GetCGRID(utils.META_DEFAULT)))
return time.Duration(0)
} else {
sessionTTLMaxDelay = maxTTLDelay.Nanoseconds() / 1000000
}
}
if sessionTTLMaxDelay != 0 {
rand.Seed(time.Now().Unix())
sesTTL += time.Duration(rand.Int63n(sessionTTLMaxDelay) * 1000000)
}
return sesTTL
}
// GetSessionTTLLastUsed retrieves SessionTTLLastUsed setting out of SMGenericEvent

View File

@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package sessionmanager
import (
"fmt"
"reflect"
"testing"
"time"
@@ -132,6 +133,26 @@ func TestSMGenericEventParseFields(t *testing.T) {
}
}
func TestSMGenericEventGetSessionTTL(t *testing.T) {
smGev := SMGenericEvent{}
smGev[utils.EVENT_NAME] = "TEST_SESSION_TTL"
cfgSesTTL := time.Duration(5 * time.Second)
if sTTL := smGev.GetSessionTTL(time.Duration(5*time.Second), nil); sTTL != cfgSesTTL {
t.Errorf("Expecting: %v, received: %v", cfgSesTTL, sTTL)
}
smGev[utils.SessionTTL] = "6s"
eSesTTL := time.Duration(6 * time.Second)
if sTTL := smGev.GetSessionTTL(time.Duration(5*time.Second), nil); sTTL != eSesTTL {
t.Errorf("Expecting: %v, received: %v", eSesTTL, sTTL)
}
sesTTLMaxDelay := time.Duration(10 * time.Second)
if sTTL := smGev.GetSessionTTL(time.Duration(5*time.Second), &sesTTLMaxDelay); sTTL == eSesTTL || sTTL > eSesTTL+sesTTLMaxDelay {
t.Errorf("Received: %v", sTTL)
} else {
fmt.Println(sTTL)
}
}
func TestSMGenericEventAsStoredCdr(t *testing.T) {
smGev := SMGenericEvent{}
smGev[utils.EVENT_NAME] = "TEST_EVENT"

View File

@@ -35,6 +35,7 @@ import (
const (
MaxTimespansInCost = 50
MaxSessionTTL = 10000 // maximum session TTL in miliseconds
)
var (
@@ -118,10 +119,8 @@ type smgSessionTerminator struct {
// setSessionTerminator installs a new terminator for a session
func (smg *SMGeneric) setSessionTerminator(s *SMGSession) {
ttl := smg.cgrCfg.SmGenericConfig.SessionTTL
if ttlEv := s.EventStart.GetSessionTTL(); ttlEv != 0 {
ttl = ttlEv
}
ttl := s.EventStart.GetSessionTTL(smg.cgrCfg.SmGenericConfig.SessionTTL,
smg.cgrCfg.SmGenericConfig.SessionTTLMaxDelay)
if ttl == 0 {
return
}
@@ -730,7 +729,9 @@ func (smg *SMGeneric) UpdateSession(gev SMGenericEvent, clnt rpcclient.RpcClient
}
smg.replicateSessionsWithID(initialCGRID, false, smg.smgReplConns)
}
smg.resetTerminatorTimer(cgrID, gev.GetSessionTTL(), gev.GetSessionTTLLastUsed(), gev.GetSessionTTLUsage())
smg.resetTerminatorTimer(cgrID,
gev.GetSessionTTL(smg.cgrCfg.SmGenericConfig.SessionTTL, smg.cgrCfg.SmGenericConfig.SessionTTLMaxDelay),
gev.GetSessionTTLLastUsed(), gev.GetSessionTTLUsage())
var lastUsed *time.Duration
var evLastUsed time.Duration
if evLastUsed, err = gev.GetLastUsed(utils.META_DEFAULT); err == nil {

View File

@@ -309,6 +309,7 @@ const (
InstanceID = "InstanceID"
ActiveGoroutines = "ActiveGoroutines"
SessionTTL = "SessionTTL"
SessionTTLMaxDelay = "SessionTTLMaxDelay"
SessionTTLLastUsed = "SessionTTLLastUsed"
SessionTTLUsage = "SessionTTLUsage"
HandlerSubstractUsage = "*substract_usage"