mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-22 07:38:45 +05:00
first draft of stale sessions protection
This commit is contained in:
@@ -135,59 +135,67 @@ func (s *Session) Close(ev engine.Event) error {
|
||||
return err
|
||||
}
|
||||
hangupTime := startTime.Add(duration)
|
||||
end := lastCC.Timespans[len(lastCC.Timespans)-1].TimeEnd
|
||||
refundDuration := end.Sub(hangupTime)
|
||||
var refundIncrements engine.Increments
|
||||
for i := len(lastCC.Timespans) - 1; i >= 0; i-- {
|
||||
ts := lastCC.Timespans[i]
|
||||
tsDuration := ts.GetDuration()
|
||||
if refundDuration <= tsDuration {
|
||||
lastRefundedIncrementIndex := 0
|
||||
for j := len(ts.Increments) - 1; j >= 0; j-- {
|
||||
increment := ts.Increments[j]
|
||||
if increment.Duration <= refundDuration {
|
||||
refundIncrements = append(refundIncrements, increment)
|
||||
refundDuration -= increment.Duration
|
||||
lastRefundedIncrementIndex = j
|
||||
}
|
||||
}
|
||||
ts.SplitByIncrement(lastRefundedIncrementIndex)
|
||||
break // do not go to other timespans
|
||||
} else {
|
||||
refundIncrements = append(refundIncrements, ts.Increments...)
|
||||
// remove the timespan entirely
|
||||
lastCC.Timespans[i] = nil
|
||||
lastCC.Timespans = lastCC.Timespans[:i]
|
||||
// continue to the next timespan with what is left to refund
|
||||
refundDuration -= tsDuration
|
||||
}
|
||||
err = s.Refund(lastCC, hangupTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// show only what was actualy refunded (stopped in timespan)
|
||||
// engine.Logger.Info(fmt.Sprintf("Refund duration: %v", initialRefundDuration-refundDuration))
|
||||
if len(refundIncrements) > 0 {
|
||||
cd := &engine.CallDescriptor{
|
||||
Direction: lastCC.Direction,
|
||||
Tenant: lastCC.Tenant,
|
||||
Category: lastCC.Category,
|
||||
Subject: lastCC.Subject,
|
||||
Account: lastCC.Account,
|
||||
Destination: lastCC.Destination,
|
||||
Increments: refundIncrements,
|
||||
}
|
||||
var response float64
|
||||
err := s.sessionManager.Rater().RefundIncrements(*cd, &response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cost := refundIncrements.GetTotalCost()
|
||||
lastCC.Cost -= cost
|
||||
lastCC.Timespans.Compress()
|
||||
}
|
||||
go s.SaveOperations()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) Refund(lastCC *engine.CallCost, hangupTime time.Time) error {
|
||||
end := lastCC.Timespans[len(lastCC.Timespans)-1].TimeEnd
|
||||
refundDuration := end.Sub(hangupTime)
|
||||
var refundIncrements engine.Increments
|
||||
for i := len(lastCC.Timespans) - 1; i >= 0; i-- {
|
||||
ts := lastCC.Timespans[i]
|
||||
tsDuration := ts.GetDuration()
|
||||
if refundDuration <= tsDuration {
|
||||
lastRefundedIncrementIndex := 0
|
||||
for j := len(ts.Increments) - 1; j >= 0; j-- {
|
||||
increment := ts.Increments[j]
|
||||
if increment.Duration <= refundDuration {
|
||||
refundIncrements = append(refundIncrements, increment)
|
||||
refundDuration -= increment.Duration
|
||||
lastRefundedIncrementIndex = j
|
||||
}
|
||||
}
|
||||
ts.SplitByIncrement(lastRefundedIncrementIndex)
|
||||
break // do not go to other timespans
|
||||
} else {
|
||||
refundIncrements = append(refundIncrements, ts.Increments...)
|
||||
// remove the timespan entirely
|
||||
lastCC.Timespans[i] = nil
|
||||
lastCC.Timespans = lastCC.Timespans[:i]
|
||||
// continue to the next timespan with what is left to refund
|
||||
refundDuration -= tsDuration
|
||||
}
|
||||
}
|
||||
// show only what was actualy refunded (stopped in timespan)
|
||||
// engine.Logger.Info(fmt.Sprintf("Refund duration: %v", initialRefundDuration-refundDuration))
|
||||
if len(refundIncrements) > 0 {
|
||||
cd := &engine.CallDescriptor{
|
||||
Direction: lastCC.Direction,
|
||||
Tenant: lastCC.Tenant,
|
||||
Category: lastCC.Category,
|
||||
Subject: lastCC.Subject,
|
||||
Account: lastCC.Account,
|
||||
Destination: lastCC.Destination,
|
||||
Increments: refundIncrements,
|
||||
}
|
||||
var response float64
|
||||
err := s.sessionManager.Rater().RefundIncrements(*cd, &response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cost := refundIncrements.GetTotalCost()
|
||||
lastCC.Cost -= cost
|
||||
lastCC.Timespans.Compress()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Nice print for session
|
||||
func (s *Session) String() string {
|
||||
sDump, _ := json.Marshal(s)
|
||||
@@ -204,14 +212,24 @@ func (s *Session) SaveOperations() {
|
||||
for _, cc := range sr.CallCosts[1:] {
|
||||
firstCC.Merge(cc)
|
||||
}
|
||||
var existingDuration int
|
||||
s.sessionManager.CdrSrv().LogCallCost(&engine.CallCostLog{
|
||||
var savedCallcostDuration int64
|
||||
err := s.sessionManager.CdrSrv().LogCallCost(&engine.CallCostLog{
|
||||
CgrId: s.eventStart.GetCgrId(),
|
||||
Source: engine.SESSION_MANAGER_SOURCE,
|
||||
RunId: sr.DerivedCharger.RunId,
|
||||
CallCost: firstCC,
|
||||
}, &existingDuration)
|
||||
// on duplicate error refound extra from existing database
|
||||
|
||||
}, &savedCallcostDuration)
|
||||
// on duplicate error refound extra period compared to existing database callcost
|
||||
// this is a protection against the case when the close event is missed for some reason
|
||||
// when the cdr arrives to cdrserver because our callcost is not there it will be rated
|
||||
// as postpaid. When the close event finally arives we have to refund everything
|
||||
if err != nil {
|
||||
hangupTime := firstCC.Timespans[0].TimeStart.Add(time.Duration(savedCallcostDuration))
|
||||
if savedCallcostDuration > 0 {
|
||||
s.Refund(firstCC, hangupTime)
|
||||
} else {
|
||||
engine.Logger.Err(fmt.Sprintf("failed to log call cost: %v", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user