diff --git a/apier/v1/apier.go b/apier/v1/apier.go index f84bd611d..615b8d0ca 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -318,7 +318,20 @@ func (self *ApierV1) ReloadScheduler(input string, reply *string) error { } func (self *ApierV1) ReloadCache(attrs utils.ApiReloadCache, reply *string) error { - if err := self.DataDb.PreCache(attrs.DestinationIds, attrs.RatingPlanIds); err!= nil { + var dstKeys, rpKeys []string + if len(attrs.DestinationIds) > 0 { + dstKeys = make([]string, len(attrs.DestinationIds)) + for idx, dId := range attrs.DestinationIds { + dstKeys[idx] = engine.DESTINATION_PREFIX+dId // Cache expects them as redis keys + } + } + if len(attrs.RatingPlanIds) > 0 { + rpKeys = make([]string, len(attrs.RatingPlanIds)) + for idx, rpId := range attrs.RatingPlanIds { + rpKeys[idx] = engine.RATING_PLAN_PREFIX+rpId + } + } + if err := self.DataDb.PreCache(dstKeys, rpKeys); err!= nil { return err } *reply = "OK" diff --git a/cmd/cgr-loader/cgr-loader.go b/cmd/cgr-loader/cgr-loader.go index 1484d961c..9177d1eb9 100644 --- a/cmd/cgr-loader/cgr-loader.go +++ b/cmd/cgr-loader/cgr-loader.go @@ -98,7 +98,7 @@ func main() { if !*toStorDb { // Connections to history and rater if *historyServer != "" { // Init scribeAgent if scribeAgent, err := history.NewProxyScribe(*historyServer, *rpcEncoding); err != nil { - log.Fatalf("Could not connect to history server: %s. Make sure you have properly configured it via -history_server flag." + err.Error()) + log.Fatalf("Could not connect to history server, error: %s. Make sure you have properly configured it via -history_server flag.", err.Error()) return } else { engine.SetHistoryScribe(scribeAgent) @@ -193,9 +193,13 @@ func main() { } // Reload cache if rater != nil { - //ToDo: only reload for destinations and rating plans we have loaded - // For this will need to export Destinations and RatingPlans loaded or a method providing their keys reply := "" + actIds,_ := loader.GetLoadedIds(engine.ACTION_TIMING_PREFIX) + if len(actIds) != 0 { // Reload scheduler first since that could take less time + if err = rater.Call("ApierV1.ReloadScheduler", "", &reply); err!=nil { + log.Fatalf("Got error on scheduler reload: %s", err.Error()) + } + } dstIds,_ := loader.GetLoadedIds(engine.DESTINATION_PREFIX) rplIds,_ := loader.GetLoadedIds(engine.RATING_PLAN_PREFIX) if err = rater.Call("ApierV1.ReloadCache", utils.ApiReloadCache{dstIds, rplIds}, &reply); err!=nil { diff --git a/console/reload_cache.go b/console/reload_cache.go new file mode 100644 index 000000000..c48c8db54 --- /dev/null +++ b/console/reload_cache.go @@ -0,0 +1,64 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2013 ITsysCOM + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import ( + "fmt" + "github.com/cgrates/cgrates/utils" +) + +func init() { + commands["reload_cache"] = &CmdReloadCache{} +} + +// Commander implementation +type CmdReloadCache struct { + rpcMethod string + rpcParams *utils.ApiReloadCache + rpcResult string +} + +// name should be exec's name +func (self *CmdReloadCache) Usage(name string) string { + return fmt.Sprintf("\n\tUsage: cgr-console [cfg_opts...{-h}] reload_cache") +} + +// set param defaults +func (self *CmdReloadCache) defaults() error { + self.rpcMethod = "ApierV1.ReloadCache" + return nil +} + +// Parses command line args and builds CmdBalance value +func (self *CmdReloadCache) FromArgs(args []string) error { + self.defaults() + return nil +} + +func (self *CmdReloadCache) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdReloadCache) RpcParams() interface{} { + return self.rpcParams +} + +func (self *CmdReloadCache) RpcResult() interface{} { + return &self.rpcResult +} diff --git a/docs/api_cache.rst b/docs/api_cache.rst new file mode 100644 index 000000000..795035f03 --- /dev/null +++ b/docs/api_cache.rst @@ -0,0 +1,66 @@ +Cache APIs +========== + +Set of cache related APIs. + + +ApierV1.ReloadCache +------------------- + +Used to enforce a cache reload. It can be fine tuned to reload individual destinations and rating plans. In order to reload all destinations and/or rating plans, one can use empty list or null values instead. + +**Request**: + +Data: + + :: + + type ApiReloadCache struct { + DestinationIds []string + RatingPlanIds []string + } + + Mandatory parameters: none + + *JSON sample*: + :: + + { + "id": 1, + "method": "ApierV1.ReloadCache", + "params": [ + { + "DestinationIds": [ + "GERMANY", + "GERMANY_MOBILE", + "FS_USERS" + ], + "RatingPlanIds": [ + "RETAIL1" + ] + } + ] + } + +**Reply**: + + Data: + :: + + string + + Possible answers: + * *OK* + + *JSON sample*: + :: + + { + "error": null, + "id": 1, + "result": "OK" + } + +**Errors**: + + ``SERVER_ERROR`` - Server error occurred. diff --git a/docs/api_scheduler.rst b/docs/api_scheduler.rst new file mode 100644 index 000000000..2900ed2f4 --- /dev/null +++ b/docs/api_scheduler.rst @@ -0,0 +1,54 @@ +Scheduler APIs +============== + +Set of scheduler related APIs. + + +ApierV1.ReloadScheduler +----------------------- + +When called CGRateS will reorder/reschedule tasks based on data available in dataDb. This command is necessary after each data load, in some cases being automated in the administration tools (eg: inside *cgr-loader*) + +**Request**: + +Data: + + :: + + string + + Mandatory parameters: none + + *JSON sample*: + :: + + { + "id": 0, + "method": "ApierV1.ReloadScheduler", + "params": [ + "" + ] + } + + +**Reply**: + + Data: + :: + + string + + Possible answers: **OK** + + *JSON sample*: + :: + + { + "error": null, + "id": 0, + "result": "OK" + } + +**Errors**: + + ``SERVER_ERROR`` - Server error occurred. diff --git a/docs/apicalls.rst b/docs/apicalls.rst index 0fb66faaa..0b6b94fdd 100644 --- a/docs/apicalls.rst +++ b/docs/apicalls.rst @@ -369,6 +369,8 @@ Administration APIs :maxdepth: 2 api_cdrs + api_cache + api_scheduler diff --git a/engine/loader_csv.go b/engine/loader_csv.go index 7f1793d83..0e0f27835 100644 --- a/engine/loader_csv.go +++ b/engine/loader_csv.go @@ -568,6 +568,14 @@ func (csvr *CSVReader) GetLoadedIds( categ string ) ([]string, error) { i++ } return keys, nil + case ACTION_TIMING_PREFIX: // actionsTimings + keys := make([]string, len(csvr.actionsTimings)) + i := 0 + for k := range csvr.actionsTimings { + keys[i] = k + i++ + } + return keys, nil } return nil, errors.New("Unsupported category") } diff --git a/engine/loader_db.go b/engine/loader_db.go index 3786d16a3..c3e216dca 100644 --- a/engine/loader_db.go +++ b/engine/loader_db.go @@ -569,6 +569,14 @@ func (dbr *DbReader) GetLoadedIds( categ string ) ([]string, error) { i++ } return keys, nil + case ACTION_TIMING_PREFIX: // actionsTimings + keys := make([]string, len(dbr.actionsTimings)) + i := 0 + for k := range dbr.actionsTimings { + keys[i] = k + i++ + } + return keys, nil } return nil, errors.New("Unsupported category") } diff --git a/engine/storage_redis.go b/engine/storage_redis.go index ac9b8a89c..1fb9a531d 100644 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -88,6 +88,7 @@ func (rs *RedisStorage) PreCache(dKeys, rpKeys []string) (err error) { } } for _, key := range dKeys { + // ToDo: cache2go.RemKey(key) if _, err = rs.GetDestination(key[len(DESTINATION_PREFIX):]); err != nil { return err } @@ -98,6 +99,7 @@ func (rs *RedisStorage) PreCache(dKeys, rpKeys []string) (err error) { } } for _, key := range rpKeys { + // ToDo: cache2go.RemKey(key) if _, err = rs.GetRatingPlan(key[len(RATING_PLAN_PREFIX):]); err != nil { return err }