diff --git a/cache2go/response_cache.go b/cache2go/response_cache.go index ec5596544..8e561379c 100644 --- a/cache2go/response_cache.go +++ b/cache2go/response_cache.go @@ -8,20 +8,25 @@ import ( var ErrNotFound = errors.New("NOT_FOUND") +type CacheItem struct { + Value interface{} + Err error +} + type ResponseCache struct { ttl time.Duration - cache map[string]interface{} + cache map[string]*CacheItem mu sync.RWMutex } func NewResponseCache(ttl time.Duration) *ResponseCache { return &ResponseCache{ ttl: ttl, - cache: make(map[string]interface{}), + cache: make(map[string]*CacheItem), } } -func (rc *ResponseCache) Cache(key string, item interface{}) { +func (rc *ResponseCache) Cache(key string, item *CacheItem) { rc.mu.Lock() rc.cache[key] = item rc.mu.Unlock() @@ -33,7 +38,7 @@ func (rc *ResponseCache) Cache(key string, item interface{}) { }() } -func (rc *ResponseCache) Get(key string) (interface{}, error) { +func (rc *ResponseCache) Get(key string) (*CacheItem, error) { rc.mu.RLock() defer rc.mu.RUnlock() item, ok := rc.cache[key] diff --git a/cache2go/response_cache_test.go b/cache2go/response_cache_test.go index dc7c4e2b2..40dc20722 100644 --- a/cache2go/response_cache_test.go +++ b/cache2go/response_cache_test.go @@ -7,16 +7,16 @@ import ( func TestRCacheSetGet(t *testing.T) { rc := NewResponseCache(5 * time.Second) - rc.Cache("test", "best") + rc.Cache("test", &CacheItem{Value: "best"}) v, err := rc.Get("test") - if err != nil || v.(string) != "best" { + if err != nil || v.Value.(string) != "best" { t.Error("Error retriving response cache: ", v, err) } } func TestRCacheExpire(t *testing.T) { rc := NewResponseCache(1 * time.Microsecond) - rc.Cache("test", "best") + rc.Cache("test", &CacheItem{Value: "best"}) time.Sleep(1 * time.Millisecond) _, err := rc.Get("test") if err == nil { diff --git a/engine/responder.go b/engine/responder.go index 7a1f1dde8..c389c6152 100644 --- a/engine/responder.go +++ b/engine/responder.go @@ -28,6 +28,7 @@ import ( "time" "github.com/cgrates/cgrates/balancer2go" + "github.com/cgrates/cgrates/cache2go" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" "github.com/cgrates/rpcclient" @@ -40,6 +41,12 @@ type SessionRun struct { CallCosts []*CallCost } +var ( + maxDebitResponseCache = cache2go.NewResponseCache(5 * time.Second) + refundIncrementsResponseCache = cache2go.NewResponseCache(5 * time.Second) + getSessionRunsResponseCache = cache2go.NewResponseCache(5 * time.Second) +) + type Responder struct { Bal *balancer2go.Balancer ExitChan chan bool @@ -89,6 +96,10 @@ func (rs *Responder) Debit(arg *CallDescriptor, reply *CallCost) (err error) { } func (rs *Responder) MaxDebit(arg *CallDescriptor, reply *CallCost) (err error) { + if item, err := maxDebitResponseCache.Get(arg.CgrId); err == nil && item != nil { + *reply = *(item.Value.(*CallCost)) + return item.Err + } if arg.Subject == "" { arg.Subject = arg.Account } @@ -98,15 +109,26 @@ func (rs *Responder) MaxDebit(arg *CallDescriptor, reply *CallCost) (err error) } else { r, e := arg.MaxDebit() if e != nil { + maxDebitResponseCache.Cache(arg.CgrId, &cache2go.CacheItem{ + Err: e, + }) return e } else if r != nil { *reply = *r } } + maxDebitResponseCache.Cache(arg.CgrId, &cache2go.CacheItem{ + Value: reply, + Err: err, + }) return } func (rs *Responder) RefundIncrements(arg *CallDescriptor, reply *float64) (err error) { + if item, err := refundIncrementsResponseCache.Get(arg.CgrId); err == nil && item != nil { + *reply = *(item.Value.(*float64)) + return item.Err + } if arg.Subject == "" { arg.Subject = arg.Account } @@ -118,6 +140,10 @@ func (rs *Responder) RefundIncrements(arg *CallDescriptor, reply *float64) (err }, arg.GetAccountKey()) *reply, err = r.(float64), e } + refundIncrementsResponseCache.Cache(arg.CgrId, &cache2go.CacheItem{ + Value: reply, + Err: err, + }) return } @@ -205,6 +231,10 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev *StoredCdr, reply *float64) err // Used by SM to get all the prepaid CallDescriptors attached to a session func (rs *Responder) GetSessionRuns(ev *StoredCdr, sRuns *[]*SessionRun) error { + if item, err := getSessionRunsResponseCache.Get(ev.CgrId); err == nil && item != nil { + *sRuns = *(item.Value.(*[]*SessionRun)) + return item.Err + } if ev.Subject == "" { ev.Subject = ev.Account } @@ -215,6 +245,9 @@ func (rs *Responder) GetSessionRuns(ev *StoredCdr, sRuns *[]*SessionRun) error { Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)} var dcs utils.DerivedChargers if err := rs.GetDerivedChargers(attrsDC, &dcs); err != nil { + getSessionRunsResponseCache.Cache(ev.CgrId, &cache2go.CacheItem{ + Err: err, + }) return err } dcs, _ = dcs.AppendDefaultRun() @@ -225,6 +258,9 @@ func (rs *Responder) GetSessionRuns(ev *StoredCdr, sRuns *[]*SessionRun) error { } startTime, err := ev.GetAnswerTime(dc.AnswerTimeField) if err != nil { + getSessionRunsResponseCache.Cache(ev.CgrId, &cache2go.CacheItem{ + Err: err, + }) return errors.New("Error parsing answer event start time") } cd := &CallDescriptor{ @@ -238,6 +274,9 @@ func (rs *Responder) GetSessionRuns(ev *StoredCdr, sRuns *[]*SessionRun) error { sesRuns = append(sesRuns, &SessionRun{DerivedCharger: dc, CallDescriptor: cd}) } *sRuns = sesRuns + getSessionRunsResponseCache.Cache(ev.CgrId, &cache2go.CacheItem{ + Value: sRuns, + }) return nil }