Merge branch 'master' of github.com:30x/apidQuota
diff --git a/api.go b/api.go
index b71bc82..b1fa4be 100644
--- a/api.go
+++ b/api.go
@@ -2,7 +2,6 @@
import (
"encoding/json"
- "fmt"
"github.com/30x/apid-core"
"github.com/30x/apidQuota/constants"
"github.com/30x/apidQuota/globalVariables"
@@ -44,7 +43,6 @@
return
}
- fmt.Println("test1")
results, err := qBucket.IncrementQuotaLimit()
if err != nil {
@@ -52,7 +50,6 @@
return
}
- fmt.Println("test2 : ", results)
respMap := results.ToAPIResponse()
respbytes, err := json.Marshal(respMap)
diff --git a/constants/constants.go b/constants/constants.go
index 459efb2..1d5449c 100644
--- a/constants/constants.go
+++ b/constants/constants.go
@@ -1,5 +1,7 @@
package constants
+import "time"
+
const (
//add to acceptedTimeUnitList in init() if case any other new timeUnit is added
@@ -19,7 +21,8 @@
QuotaTypeCalendar = "calendar" // after start time
QuotaTypeRollingWindow = "rollingwindow" // in the past "window" time
- cacheKeyDelimiter = "|"
+ CacheKeyDelimiter = "|"
+ CacheTTL = time.Minute * 1
UnableToParseBody = "unable_to_parse_body"
UnMarshalJSONError = "unmarshal_json_error"
ErrorConvertReqBodyToEntity = "error_convert_reqBody_to_entity"
diff --git a/globalVariables/globalVariables.go b/globalVariables/globalVariables.go
index 50a4df0..2891ca9 100644
--- a/globalVariables/globalVariables.go
+++ b/globalVariables/globalVariables.go
@@ -1,6 +1,8 @@
package globalVariables
-import "github.com/30x/apid-core"
+import (
+ "github.com/30x/apid-core"
+)
var (
Log apid.LogService
diff --git a/quotaBucket/apiUtil.go b/quotaBucket/apiUtil.go
index 27d964d..b739cad 100644
--- a/quotaBucket/apiUtil.go
+++ b/quotaBucket/apiUtil.go
@@ -4,6 +4,7 @@
"errors"
"reflect"
"time"
+ "github.com/30x/apidQuota/constants"
)
const (
@@ -22,7 +23,8 @@
expiresAt int64
}
-func (qBucket *QuotaBucket) FromAPIRequest(quotaBucketMap map[string]interface{}) error {
+func (qBucketRequest *QuotaBucket) FromAPIRequest(quotaBucketMap map[string]interface{}) error {
+ var cacheKey string
var edgeOrgID, id, timeUnit, quotaType string
var interval int
var startTime, maxCount, weight int64
@@ -48,6 +50,7 @@
}
id = value.(string)
+ cacheKey = edgeOrgID + constants.CacheKeyDelimiter + id
value, ok = quotaBucketMap["interval"]
if !ok {
return errors.New(`missing field: 'interval' is required`)
@@ -159,18 +162,29 @@
if syncTimeType := reflect.TypeOf(syncTimeValue); syncTimeType.Kind() != reflect.Float64 {
return errors.New(`invalid type : 'syncTimeInSec' should be a number`)
}
- syncTimeFloat := value.(float64)
+ syncTimeFloat := syncTimeValue.(float64)
syncTimeInt := int64(syncTimeFloat)
- newQBucket, err = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel,
- startTime, maxCount, weight, distributed, synchronous, syncTimeInt, -1)
- if err != nil {
- return errors.New("error creating quotaBucket: " + err.Error())
- }
- qBucket.quotaBucketData = newQBucket.quotaBucketData
- if err := qBucket.Validate(); err != nil {
- return errors.New("failed in Validating the quotaBucket: " + err.Error())
+ //try to retrieve from cache
+ newQBucket, ok = getFromCache(cacheKey)
+
+ if !ok {
+ newQBucket, err = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel,
+ startTime, maxCount, weight, distributed, synchronous, syncTimeInt, -1)
+ if err != nil {
+ return errors.New("error creating quotaBucket: " + err.Error())
+ }
+
+ qBucketRequest.quotaBucketData = newQBucket.quotaBucketData
+
+ if err := qBucketRequest.Validate(); err != nil {
+ return errors.New("failed in Validating the quotaBucket: " + err.Error())
+ }
+
+ addToCache(qBucketRequest)
+ return nil
}
+ qBucketRequest.quotaBucketData = newQBucket.quotaBucketData
return nil
@@ -180,48 +194,75 @@
}
syncMsgCountFloat := value.(float64)
syncMsgCountInt := int64(syncMsgCountFloat)
- newQBucket, err = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel,
- startTime, maxCount, weight, distributed, synchronous, -1, syncMsgCountInt)
- if err != nil {
- return errors.New("error creating quotaBucket: " + err.Error())
- }
- qBucket.quotaBucketData = newQBucket.quotaBucketData
+ //try to retrieve from cache
+ newQBucket, ok = getFromCache(cacheKey)
- if err := qBucket.Validate(); err != nil {
- return errors.New("failed in Validating the quotaBucket: " + err.Error())
+ if !ok {
+ newQBucket, err = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel,
+ startTime, maxCount, weight, distributed, synchronous, -1, syncMsgCountInt)
+ if err != nil {
+ return errors.New("error creating quotaBucket: " + err.Error())
+ }
+ qBucketRequest.quotaBucketData = newQBucket.quotaBucketData
+
+ if err := qBucketRequest.Validate(); err != nil {
+ return errors.New("failed in Validating the quotaBucket: " + err.Error())
+ }
+
+ addToCache(qBucketRequest)
+ return nil
+
}
+ qBucketRequest.quotaBucketData = newQBucket.quotaBucketData
return nil
}
}
- //for synchronous quotaBucket
- newQBucket, err = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel,
- startTime, maxCount, weight, distributed, synchronous, -1, -1)
- if err != nil {
- return errors.New("error creating quotaBucket: " + err.Error())
- }
- qBucket.quotaBucketData = newQBucket.quotaBucketData
+ //try to retrieve from cache
+ newQBucket, ok = getFromCache(cacheKey)
- if err := qBucket.Validate(); err != nil {
- return errors.New("failed in Validating the quotaBucket: " + err.Error())
+ if !ok {
+ //for synchronous quotaBucket
+ newQBucket, err = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel,
+ startTime, maxCount, weight, distributed, synchronous, -1, -1)
+ if err != nil {
+ return errors.New("error creating quotaBucket: " + err.Error())
+ }
+ qBucketRequest.quotaBucketData = newQBucket.quotaBucketData
+
+ if err := qBucketRequest.Validate(); err != nil {
+ return errors.New("failed in Validating the quotaBucket: " + err.Error())
+ }
+ addToCache(qBucketRequest)
+ return nil
}
+ qBucketRequest.quotaBucketData = newQBucket.quotaBucketData
return nil
}
- //for non distributed quotaBucket
- newQBucket, err = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel,
- startTime, maxCount, weight, distributed, false, -1, -1)
- if err != nil {
- return errors.New("error creating quotaBucket: " + err.Error())
- }
+ //retrieveFromCache.
+ newQBucket, ok = getFromCache(cacheKey)
+ qBucketRequest.quotaBucketData = newQBucket.quotaBucketData
- qBucket.quotaBucketData = newQBucket.quotaBucketData
+ if !ok {
+ //for non distributed quotaBucket
+ newQBucket, err = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel,
+ startTime, maxCount, weight, distributed, false, -1, -1)
+ if err != nil {
+ return errors.New("error creating quotaBucket: " + err.Error())
- if err := qBucket.Validate(); err != nil {
- return errors.New("failed in Validating the quotaBucket: " + err.Error())
+ }
+
+ qBucketRequest.quotaBucketData = newQBucket.quotaBucketData
+
+ if err := qBucketRequest.Validate(); err != nil {
+ return errors.New("failed in Validating the quotaBucket: " + err.Error())
+ }
+
+ addToCache(qBucketRequest)
}
return nil
diff --git a/quotaBucket/quotaBucket.go b/quotaBucket/quotaBucket.go
index ca22202..0a06b21 100644
--- a/quotaBucket/quotaBucket.go
+++ b/quotaBucket/quotaBucket.go
@@ -3,6 +3,7 @@
import (
"errors"
"github.com/30x/apidQuota/constants"
+ "github.com/30x/apidQuota/globalVariables"
"strings"
"time"
)
@@ -86,6 +87,9 @@
Synchronous bool
SyncTimeInSec int64
SyncMessageCount int64
+ AsyncMessageCounter int64
+ QTicker *time.Ticker
+
}
type QuotaBucket struct {
@@ -113,6 +117,8 @@
Synchronous: synchronous,
SyncTimeInSec: syncTimeInSec,
SyncMessageCount: syncMessageCount,
+ AsyncMessageCounter: int64(-1),
+ QTicker: &time.Ticker{},
}
quotaBucket := &QuotaBucket{
@@ -123,6 +129,23 @@
if err != nil {
return nil, err
}
+
+ //for async SetAsyncMessageCounter to 0 and also start the scheduler
+ if distributed && !synchronous{
+ quotaBucket.SetAsyncMessageCounter(0)
+ quotaBucket.quotaBucketData.QTicker = time.NewTicker(time.Second)
+ go func() {
+ count := 0
+ for t := range quotaBucket.quotaBucketData.QTicker.C {
+ globalVariables.Log.Debug("t: : ", t.String())
+ if count > 10 {
+ quotaBucket.getTicker().Stop()
+ }
+ count += 1
+ }
+ }()
+ }
+
return quotaBucket, nil
}
@@ -194,6 +217,13 @@
return q.quotaBucketData.Synchronous
}
+func (qbucket *QuotaBucket) SetAsyncMessageCounter(count int64) {
+ qbucket.quotaBucketData.AsyncMessageCounter = count
+}
+
+func (q *QuotaBucket) getTicker() *time.Ticker {
+ return q.quotaBucketData.QTicker
+}
//Calls setCurrentPeriod if DescriptorType is 'rollingWindow' or period.endTime is before now().
// It is required to setPeriod while incrementing the count.
func (q *QuotaBucket) GetPeriod() (*QuotaPeriod, error) {
diff --git a/quotaBucket/quotaBucketType.go b/quotaBucket/quotaBucketType.go
index b905bd7..3c73d46 100644
--- a/quotaBucket/quotaBucketType.go
+++ b/quotaBucket/quotaBucketType.go
@@ -2,7 +2,6 @@
import (
"errors"
- "fmt"
"github.com/30x/apidQuota/services"
)
@@ -43,7 +42,6 @@
func (sQuotaBucket SynchronousQuotaBucketType) incrementQuotaCount(q *QuotaBucket) (*QuotaBucketResults, error) {
- fmt.Println("increment count for sync")
maxCount := q.GetMaxCount()
exceededCount := false
allowedCount := int64(0)
@@ -104,15 +102,13 @@
syncTimeInSec int64
}
-func (quotaBucketType AsynchronousQuotaBucketType) resetCount(qBucket *QuotaBucket) error {
+func (quotaBucketType AsynchronousQuotaBucketType) resetCount(q *QuotaBucket) error {
//yet to implement
return nil
}
-func (quotaBucketType AsynchronousQuotaBucketType) incrementQuotaCount(qBucket *QuotaBucket) (*QuotaBucketResults, error) {
+func (quotaBucketType AsynchronousQuotaBucketType) incrementQuotaCount(q *QuotaBucket) (*QuotaBucketResults, error) {
//getCount()
- fmt.Println("increment count for async")
-
return nil, nil
}
@@ -127,7 +123,6 @@
return nil
}
func (sQuotaBucket NonDistributedQuotaBucketType) incrementQuotaCount(qBucket *QuotaBucket) (*QuotaBucketResults, error) {
- fmt.Println("increment count for nondistributed.")
return nil, nil
}
diff --git a/quotaBucket/quotaBucket_test.go b/quotaBucket/quotaBucket_test.go
index 3a8fcfb..08b580c 100644
--- a/quotaBucket/quotaBucket_test.go
+++ b/quotaBucket/quotaBucket_test.go
@@ -407,23 +407,6 @@
Fail("Exprected true, returned: false")
}
- //end Time in period is now // cant set end time to now and tes.. by the time it evaluates isCurrentPeriod the period.endTime will be before time.now()
- //fmt.Println("entTIme is now : ")
- //startTime = time.Now().Unix()
- //period = NewQuotaPeriod(time.Now().AddDate(0,-1,-1).Unix(),
- // time.Now().AddDate(0,0,-1).Unix(),
- // time.Now().Unix())
- //quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType)
- //err = quotaBucket.Validate()
- //if err != nil {
- // Fail("no error expected but got error: " + err.Error())
- //}
- //
- //period.IsCurrentPeriod(quotaBucket)
- //if ok := period.IsCurrentPeriod(quotaBucket); !ok{
- // Fail("Exprected true, returned: false")
- //}
-
//end Time in period is after now
startTime = time.Now().UTC().Unix()
quotaBucket, err = NewQuotaBucket(edgeOrgID, id, interval, timeUnit,
diff --git a/quotaBucket/quotaCache.go b/quotaBucket/quotaCache.go
new file mode 100644
index 0000000..4c8338e
--- /dev/null
+++ b/quotaBucket/quotaCache.go
@@ -0,0 +1,68 @@
+package quotaBucket
+
+import (
+ "github.com/30x/apidQuota/constants"
+ "time"
+ "sync"
+)
+
+var quotaCachelock = sync.RWMutex{}
+
+type quotaBucketCache struct {
+ qBucket *QuotaBucket
+ expiryTime int64
+}
+
+var quotaCache map[string]quotaBucketCache
+
+func init() {
+ quotaCache = make(map[string]quotaBucketCache)
+}
+
+func getFromCache(cacheKey string) (*QuotaBucket,bool) {
+ quotaCachelock.Lock()
+ defer quotaCachelock.Unlock()
+ qBucketCache, ok := quotaCache[cacheKey]
+ if !ok {
+ return nil,false
+ }
+
+ isExpired := time.Unix(qBucketCache.expiryTime, 0).Before(time.Now().UTC())
+ if isExpired {
+ removeFromCache(cacheKey, qBucketCache)
+ return nil, false
+ }
+
+ // update expiry time every time you access.
+ ttl := time.Now().UTC().Add(constants.CacheTTL).Unix()
+ qBucketCache.expiryTime = ttl
+ quotaCache[cacheKey] = qBucketCache
+
+ return qBucketCache.qBucket, true
+
+}
+
+func removeFromCache(cacheKey string, qBucketCache quotaBucketCache) {
+ //for async Stop the scheduler.
+ if qBucketCache.qBucket.Distributed && !qBucketCache.qBucket.IsSynchronous(){
+ qBucketCache.qBucket.getTicker().Stop()
+ }
+
+ quotaCachelock.Lock()
+ delete(quotaCache,cacheKey)
+ quotaCachelock.Unlock()
+}
+
+func addToCache(qBucketToAdd *QuotaBucket) {
+ cacheKey := qBucketToAdd.GetEdgeOrgID() + constants.CacheKeyDelimiter + qBucketToAdd.GetID()
+ ttl := time.Now().UTC().Add(constants.CacheTTL).Unix()
+
+ qCacheData := quotaBucketCache{
+ qBucket: qBucketToAdd,
+ expiryTime: ttl,
+ }
+
+ quotaCachelock.Lock()
+ quotaCache[cacheKey] = qCacheData
+ quotaCachelock.Unlock()
+}
diff --git a/services/counterServiceHelper.go b/services/counterServiceHelper.go
index a2c95aa..21fea87 100644
--- a/services/counterServiceHelper.go
+++ b/services/counterServiceHelper.go
@@ -4,7 +4,6 @@
"bytes"
"encoding/json"
"errors"
- "fmt"
"github.com/30x/apidQuota/constants"
"github.com/30x/apidQuota/globalVariables"
"io/ioutil"
@@ -32,7 +31,6 @@
}
func IncrementAndGetCount(orgID string, quotaKey string, count int64, startTimeInt int64, endTimeInt int64) (int64, error) {
- fmt.Println("calling counter service")
headers := http.Header{}
headers.Set("Accept", "application/json")
headers.Set("Content-Type", "application/json")
@@ -56,9 +54,6 @@
reqBody[startTime] = startTimeInt * int64(1000)
reqBody[endTime] = endTimeInt * int64(1000)
- fmt.Println("startTime: ", startTimeInt)
- fmt.Println("endTime: ", endTimeInt)
-
reqBodyBytes, err := json.Marshal(reqBody)
if err != nil {
return 0, errors.New(constants.MarshalJSONError)
@@ -73,7 +68,6 @@
ContentLength: int64(contentLength),
}
- fmt.Println("req: ", request)
resp, err := client.Do(request)
if err != nil {
@@ -104,7 +98,6 @@
if !ok {
return 0, errors.New(`invalid response from counter service. field 'count' not sent in the response`)
}
- fmt.Println("respcount: ", respCount)
globalVariables.Log.Debug("responseCount: ", respCount)