mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
CDRS to only process rawCdr synchronously and all the rest async to speed up the process and avoid struct locks - if any
This commit is contained in:
@@ -201,6 +201,45 @@ func TestV2CdrsMysqlCountCdrs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test Prepaid CDRs without previous costs being calculated
|
||||
func TestV2CdrsMysqlProcessPrepaidCdr(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
var reply string
|
||||
cdrs := []*engine.StoredCdr{
|
||||
&engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
|
||||
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
RatedAccount: "dan", RatedSubject: "dans", Rated: true,
|
||||
},
|
||||
&engine.StoredCdr{CgrId: utils.Sha1("abcdeftg2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
|
||||
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
RatedAccount: "dan", RatedSubject: "dans",
|
||||
},
|
||||
&engine.StoredCdr{CgrId: utils.Sha1("aererfddf2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
|
||||
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
RatedAccount: "dan", RatedSubject: "dans",
|
||||
},
|
||||
}
|
||||
tStart := time.Now()
|
||||
for _, cdr := range cdrs {
|
||||
if err := cdrsRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Unexpected reply received: ", reply)
|
||||
}
|
||||
}
|
||||
if processDur := time.Now().Sub(tStart); processDur > 1*time.Second {
|
||||
t.Error("Unexpected processing time", processDur)
|
||||
}
|
||||
}
|
||||
|
||||
func TestV2CdrsMysqlKillEngine(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
|
||||
@@ -199,6 +199,45 @@ func TestV2CdrsPsqlCountCdrs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test Prepaid CDRs without previous costs being calculated
|
||||
func TestV2CdrsPsqlProcessPrepaidCdr(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
var reply string
|
||||
cdrs := []*engine.StoredCdr{
|
||||
&engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
|
||||
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
RatedAccount: "dan", RatedSubject: "dans", Rated: true,
|
||||
},
|
||||
&engine.StoredCdr{CgrId: utils.Sha1("abcdeftg2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
|
||||
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
RatedAccount: "dan", RatedSubject: "dans",
|
||||
},
|
||||
&engine.StoredCdr{CgrId: utils.Sha1("aererfddf2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
|
||||
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
RatedAccount: "dan", RatedSubject: "dans",
|
||||
},
|
||||
}
|
||||
tStart := time.Now()
|
||||
for _, cdr := range cdrs {
|
||||
if err := cdrsPsqlRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Unexpected reply received: ", reply)
|
||||
}
|
||||
}
|
||||
if processDur := time.Now().Sub(tStart); processDur > 1*time.Second {
|
||||
t.Error("Unexpected processing time", processDur)
|
||||
}
|
||||
}
|
||||
|
||||
func TestV2CdrsPsqlKillEngine(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
|
||||
194
engine/cdrs.go
194
engine/cdrs.go
@@ -32,6 +32,14 @@ import (
|
||||
|
||||
var cdrServer *CdrServer // Share the server so we can use it in http handlers
|
||||
|
||||
type CallCostLog struct {
|
||||
CgrId string
|
||||
Source string
|
||||
RunId string
|
||||
CallCost *CallCost
|
||||
CheckDuplicate bool
|
||||
}
|
||||
|
||||
// Handler for generic cgr cdr http
|
||||
func cgrCdrHandler(w http.ResponseWriter, r *http.Request) {
|
||||
cgrCdr, err := NewCgrCdrFromHttpReq(r)
|
||||
@@ -39,11 +47,9 @@ func cgrCdrHandler(w http.ResponseWriter, r *http.Request) {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Could not create CDR entry: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
if err := cdrServer.rateStoreStatsReplicate(cgrCdr.AsStoredCdr()); err != nil {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Errors when storing CDR entry: %s", err.Error()))
|
||||
}
|
||||
}()
|
||||
if err := cdrServer.processCdr(cgrCdr.AsStoredCdr()); err != nil {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Errors when storing CDR entry: %s", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for fs http
|
||||
@@ -54,29 +60,13 @@ func fsCdrHandler(w http.ResponseWriter, r *http.Request) {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Could not create CDR entry: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
if err := cdrServer.rateStoreStatsReplicate(fsCdr.AsStoredCdr()); err != nil {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Errors when storing CDR entry: %s", err.Error()))
|
||||
}
|
||||
}()
|
||||
if err := cdrServer.processCdr(fsCdr.AsStoredCdr()); err != nil {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Errors when storing CDR entry: %s", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
func NewCdrServer(cgrCfg *config.CGRConfig, cdrDb CdrStorage, rater Connector, stats StatsInterface) (*CdrServer, error) {
|
||||
return &CdrServer{cgrCfg: cgrCfg, cdrDb: cdrDb, rater: rater, stats: stats, callCostMutex: new(sync.RWMutex)}, nil
|
||||
/*
|
||||
if cfg.CDRSStats != "" {
|
||||
if cfg.CDRSStats != utils.INTERNAL {
|
||||
if s, err := NewProxyStats(cfg.CDRSStats); err == nil {
|
||||
stats = s
|
||||
} else {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Errors connecting to CDRS stats service : %s", err.Error()))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// disable stats for cdrs
|
||||
stats = nil
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
type CdrServer struct {
|
||||
@@ -95,7 +85,8 @@ func (self *CdrServer) RegisterHanlersToServer(server *Server) {
|
||||
|
||||
// RPC method, used to internally process CDR
|
||||
func (self *CdrServer) ProcessCdr(cdr *StoredCdr) error {
|
||||
return self.rateStoreStatsReplicate(cdr)
|
||||
Logger.Debug(fmt.Sprintf("ProcessCdr, cdr: %+v", cdr))
|
||||
return self.processCdr(cdr)
|
||||
}
|
||||
|
||||
// RPC method, used to process external CDRs
|
||||
@@ -104,21 +95,13 @@ func (self *CdrServer) ProcessExternalCdr(cdr *ExternalCdr) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return self.rateStoreStatsReplicate(storedCdr)
|
||||
}
|
||||
|
||||
type CallCostLog struct {
|
||||
CgrId string
|
||||
Source string
|
||||
RunId string
|
||||
CallCost *CallCost
|
||||
CheckDuplicate bool
|
||||
return self.processCdr(storedCdr)
|
||||
}
|
||||
|
||||
// RPC method, used to log callcosts to db
|
||||
func (self *CdrServer) LogCallCost(ccl *CallCostLog) error {
|
||||
if ccl.CheckDuplicate {
|
||||
self.callCostMutex.Lock() // Avoid writing between checkDuplicate and logCallCost
|
||||
self.callCostMutex.Lock() // Avoid writing between checkDuplicate and logCallCost, FixMe: add the mutex per CgrId
|
||||
defer self.callCostMutex.Unlock()
|
||||
cc, err := self.cdrDb.GetCallCostLog(ccl.CgrId, ccl.Source, ccl.RunId)
|
||||
if err != nil && err != gorm.RecordNotFound {
|
||||
@@ -152,7 +135,7 @@ func (self *CdrServer) RateCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqT
|
||||
return err
|
||||
}
|
||||
for _, cdr := range cdrs {
|
||||
if err := self.rateStoreStatsReplicate(cdr); err != nil {
|
||||
if err := self.processCdr(cdr); err != nil {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Processing CDR %+v, got error: %s", cdr, err.Error()))
|
||||
}
|
||||
}
|
||||
@@ -160,102 +143,62 @@ func (self *CdrServer) RateCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqT
|
||||
}
|
||||
|
||||
// Returns error if not able to properly store the CDR, mediation is async since we can always recover offline
|
||||
func (self *CdrServer) rateStoreStatsReplicate(storedCdr *StoredCdr) (err error) {
|
||||
func (self *CdrServer) processCdr(storedCdr *StoredCdr) (err error) {
|
||||
Logger.Debug(fmt.Sprintf("processCdr, cdr: %+v", storedCdr))
|
||||
if storedCdr.ReqType == utils.META_NONE {
|
||||
return nil
|
||||
}
|
||||
cdrs := []*StoredCdr{storedCdr}
|
||||
if self.rater != nil && !storedCdr.Rated { // Rate CDR
|
||||
if cdrs, err = self.deriveAndRateCdr(storedCdr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if self.cgrCfg.CDRSStoreCdrs { // Store CDRs
|
||||
// Store RawCdr
|
||||
if self.cgrCfg.CDRSStoreCdrs { // Store RawCDRs, this we do sync so we can reply with the status
|
||||
if err := self.cdrDb.SetCdr(storedCdr); err != nil { // Only original CDR stored in primary table, no derived
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Storing primary CDR %+v, got error: %s", storedCdr, err.Error()))
|
||||
}
|
||||
// Store rated CDRs (including derived)
|
||||
for _, cdr := range cdrs {
|
||||
if len(cdr.MediationRunId) == 0 { // Do not store rating info for rawCDRs
|
||||
continue
|
||||
}
|
||||
go self.deriveRateStoreStatsReplicate(storedCdr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns error if not able to properly store the CDR, mediation is async since we can always recover offline
|
||||
func (self *CdrServer) deriveRateStoreStatsReplicate(storedCdr *StoredCdr) error {
|
||||
cdrRuns, err := self.deriveCdrs(storedCdr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, cdr := range cdrRuns {
|
||||
// Rate CDR
|
||||
if self.rater != nil && !cdr.Rated {
|
||||
if err := self.rateCDR(cdr); err != nil {
|
||||
cdr.Cost = -1.0 // If there was an error, mark the CDR
|
||||
cdr.ExtraInfo = err.Error()
|
||||
}
|
||||
}
|
||||
if self.cgrCfg.CDRSStoreCdrs { // Store CDRs
|
||||
// Store RatedCDR
|
||||
if err := self.cdrDb.SetRatedCdr(cdr); err != nil {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Storing rated CDR %+v, got error: %s", cdr, err.Error()))
|
||||
}
|
||||
// Store CostDetails
|
||||
if cdr.Rated || utils.IsSliceMember([]string{utils.RATED, utils.META_RATED}, cdr.ReqType) { // Account related CDRs are saved automatically, so save the others here if requested
|
||||
if err := self.cdrDb.LogCallCost(cdr.CgrId, utils.CDRS_SOURCE, cdr.MediationRunId, storedCdr.CostDetails); err != nil {
|
||||
if err := self.cdrDb.LogCallCost(cdr.CgrId, utils.CDRS_SOURCE, cdr.MediationRunId, cdr.CostDetails); err != nil {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Storing costs for CDR %+v, costDetails: %+v, got error: %s", cdr, cdr.CostDetails, err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.stats != nil { // Send CDR to stats
|
||||
for _, cdr := range cdrs {
|
||||
go func(storedCdr *StoredCdr) {
|
||||
if err := self.stats.AppendCDR(storedCdr, nil); err != nil {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Could not append cdr to stats: %s", err.Error()))
|
||||
}
|
||||
}(cdr)
|
||||
// Attach CDR to stats
|
||||
if self.stats != nil { // Send CDR to stats
|
||||
if err := self.stats.AppendCDR(cdr, nil); err != nil {
|
||||
Logger.Err(fmt.Sprintf("<CDRS> Could not append cdr to stats: %s", err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.cgrCfg.CDRSCdrReplication != nil {
|
||||
for _, cdr := range cdrs {
|
||||
if self.cgrCfg.CDRSCdrReplication != nil {
|
||||
self.replicateCdr(cdr)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Derive the original CDR based on derivedCharging rules and calculate costs for each. Returns the results
|
||||
func (self *CdrServer) deriveAndRateCdr(storedCdr *StoredCdr) ([]*StoredCdr, error) {
|
||||
cdrRuns, err := self.deriveCdrs(storedCdr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cdr := range cdrRuns {
|
||||
if err := self.rateCDR(cdr); err != nil {
|
||||
cdr.Cost = -1.0 // If there was an error, mark the CDR
|
||||
cdr.ExtraInfo = err.Error()
|
||||
}
|
||||
}
|
||||
return cdrRuns, nil
|
||||
}
|
||||
|
||||
// Retrive the cost from engine
|
||||
func (self *CdrServer) getCostFromRater(storedCdr *StoredCdr) (*CallCost, error) {
|
||||
//if storedCdr.Usage == time.Duration(0) { // failed call, nil cost
|
||||
// return nil, nil // No costs present, better than empty call cost since could lead us to 0 costs
|
||||
//}
|
||||
cc := new(CallCost)
|
||||
var err error
|
||||
cd := &CallDescriptor{
|
||||
TOR: storedCdr.TOR,
|
||||
Direction: storedCdr.Direction,
|
||||
Tenant: storedCdr.Tenant,
|
||||
Category: storedCdr.Category,
|
||||
Subject: storedCdr.Subject,
|
||||
Account: storedCdr.Account,
|
||||
Destination: storedCdr.Destination,
|
||||
TimeStart: storedCdr.AnswerTime,
|
||||
TimeEnd: storedCdr.AnswerTime.Add(storedCdr.Usage),
|
||||
DurationIndex: storedCdr.Usage,
|
||||
}
|
||||
if utils.IsSliceMember([]string{utils.META_PSEUDOPREPAID, utils.META_POSTPAID, utils.META_PREPAID, utils.PSEUDOPREPAID, utils.POSTPAID, utils.PREPAID}, storedCdr.ReqType) { // Prepaid - Cost can be recalculated in case of missing records from SM
|
||||
if err = self.rater.Debit(cd, cc); err == nil { // Debit has occured, we are forced to write the log, even if CDR store is disabled
|
||||
self.cdrDb.LogCallCost(storedCdr.CgrId, utils.CDRS_SOURCE, storedCdr.MediationRunId, cc)
|
||||
}
|
||||
} else {
|
||||
err = self.rater.GetCost(cd, cc)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cc, nil
|
||||
}
|
||||
|
||||
func (self *CdrServer) deriveCdrs(storedCdr *StoredCdr) ([]*StoredCdr, error) {
|
||||
Logger.Debug(fmt.Sprintf("deriveCdrs, cdr: %+v", storedCdr))
|
||||
if len(storedCdr.MediationRunId) == 0 {
|
||||
storedCdr.MediationRunId = utils.META_DEFAULT
|
||||
}
|
||||
@@ -306,19 +249,54 @@ func (self *CdrServer) deriveCdrs(storedCdr *StoredCdr) ([]*StoredCdr, error) {
|
||||
return cdrRuns, nil
|
||||
}
|
||||
|
||||
// Retrive the cost from engine
|
||||
func (self *CdrServer) getCostFromRater(storedCdr *StoredCdr) (*CallCost, error) {
|
||||
//if storedCdr.Usage == time.Duration(0) { // failed call, nil cost
|
||||
// return nil, nil // No costs present, better than empty call cost since could lead us to 0 costs
|
||||
//}
|
||||
cc := new(CallCost)
|
||||
var err error
|
||||
cd := &CallDescriptor{
|
||||
TOR: storedCdr.TOR,
|
||||
Direction: storedCdr.Direction,
|
||||
Tenant: storedCdr.Tenant,
|
||||
Category: storedCdr.Category,
|
||||
Subject: storedCdr.Subject,
|
||||
Account: storedCdr.Account,
|
||||
Destination: storedCdr.Destination,
|
||||
TimeStart: storedCdr.AnswerTime,
|
||||
TimeEnd: storedCdr.AnswerTime.Add(storedCdr.Usage),
|
||||
DurationIndex: storedCdr.Usage,
|
||||
}
|
||||
if utils.IsSliceMember([]string{utils.META_PSEUDOPREPAID, utils.META_POSTPAID, utils.META_PREPAID, utils.PSEUDOPREPAID, utils.POSTPAID, utils.PREPAID}, storedCdr.ReqType) { // Prepaid - Cost can be recalculated in case of missing records from SM
|
||||
if err = self.rater.Debit(cd, cc); err == nil { // Debit has occured, we are forced to write the log, even if CDR store is disabled
|
||||
self.cdrDb.LogCallCost(storedCdr.CgrId, utils.CDRS_SOURCE, storedCdr.MediationRunId, cc)
|
||||
}
|
||||
} else {
|
||||
err = self.rater.GetCost(cd, cc)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cc, nil
|
||||
}
|
||||
|
||||
func (self *CdrServer) rateCDR(storedCdr *StoredCdr) error {
|
||||
Logger.Debug(fmt.Sprintf("rateCDR, cdr: %+v", storedCdr))
|
||||
var qryCC *CallCost
|
||||
var err error
|
||||
if utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID}, storedCdr.ReqType) { // ToDo: Get rid of PREPAID as soon as we don't want to support it backwards
|
||||
// Should be previously calculated and stored in DB
|
||||
delay := utils.Fib()
|
||||
for i := 0; i < 4; i++ {
|
||||
Logger.Debug(fmt.Sprintf("rateCDR, cdr: %+v, loopIndex: %d", storedCdr, i))
|
||||
qryCC, err = self.cdrDb.GetCallCostLog(storedCdr.CgrId, utils.SESSION_MANAGER_SOURCE, storedCdr.MediationRunId)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(delay())
|
||||
}
|
||||
Logger.Debug(fmt.Sprintf("rateCDR, cdr: %+v, out of loop", storedCdr))
|
||||
if err != nil && err == gorm.RecordNotFound { //calculate CDR as for pseudoprepaid
|
||||
Logger.Warning(fmt.Sprintf("<Cdrs> WARNING: Could not find CallCostLog for cgrid: %s, source: %s, runid: %s, will recalculate", storedCdr.CgrId, utils.SESSION_MANAGER_SOURCE, storedCdr.MediationRunId))
|
||||
qryCC, err = self.getCostFromRater(storedCdr)
|
||||
|
||||
@@ -129,7 +129,7 @@ func TestCdrsHttpJsonRpcCdrReplication(t *testing.T) {
|
||||
rcvedCdrs[0].MediationRunId != testCdr1.MediationRunId ||
|
||||
rcvedCdrs[0].Cost != testCdr1.Cost ||
|
||||
!reflect.DeepEqual(rcvedCdrs[0].ExtraFields, testCdr1.ExtraFields) {
|
||||
t.Error("Received: ", rcvedCdrs[0])
|
||||
t.Errorf("Received: %+v", rcvedCdrs[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/apier/v1"
|
||||
//"github.com/cgrates/cgrates/apier/v1"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
@@ -870,6 +870,7 @@ func TestTutLocalLeastCost(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Make sure all stats queues were updated
|
||||
func TestTutLocalCdrStatsAfter(t *testing.T) {
|
||||
if !*testLocal {
|
||||
@@ -913,6 +914,7 @@ func TestTutLocalCdrStatsAfter(t *testing.T) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
func TestTutLocalStopCgrEngine(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user