Support A2Billing :

provided by Star2Billing S.L.

Support A2Billing :
It is currently Mon Dec 18, 2017 2:47 pm
VoIP Billing solution


All times are UTC




Post new topic Reply to topic  [ 22 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Logic behind simultaneous calls and maintain the balance
PostPosted: Sat Jun 14, 2008 9:58 pm 
Offline

Joined: Sun Jan 21, 2007 1:33 am
Posts: 22
I would like to know the logic behind handling the simultaneous calls on a prepaid card and maintain the balance to make sure the balance is not going below zero. I found from the callback that the call is not getting disconnected even if the balance is below zero for the prepaid cards.

I dig into the code but didn't find any logic to keep track of simultaneous calls and reserve the balance.. I will appreciate if Areski or someone else share the info.

Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 14, 2008 11:47 pm 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
To tell you truth. At this time, simultaneous calls will always be able to bring the balance down below zero. That will be caused by long duration calls that stays simultaneous. Short calls will give the chance to update the balance more often and eventually new calls will be prevented if the balance reaches zero. But even then, long duration calls that might still be ongoing will cause the balance to be updated at the end of the calls and to become a negative balance.

Luckily, this might be soon part of history. Work is being done to prevent that.

Cheers


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 15, 2008 7:14 am 
Offline

Joined: Sun Jan 21, 2007 1:33 am
Posts: 22
Hmm... now i got it.. Because i have looked at many billing systems and found that this functionality is missing... But few months ago i wrote my own billing in java and implemented this functionality for this kind of issue... probably you can do the same but i am not sure how feasible it is with php.

The logic i have used is... reserve and capture... i have a db table which will contain 4 columns.. first cardnumber, unique id(or channel name), reserved amount, datetime. when the billing system initiate a call, it reserves some money for say 5 mins (you can set this parameter in config file) and set the absolute timeout for 5 mins even they have balance to make call for more than 5 mins. So the call is dialled, insert a row in db to mark the amount for 5 mins call in the reserved table and i spawn a thread timer which will check the balance after 4min and 57 secs and if the customer has balance reset the timeout to another 5 mins etc.

The timer task check the reserved table for that card number (if there are more than one call going, just group by card number to collect the total balance and subtract that money from the real balance before making another call or extend timeout). Once the call is completed, get the real "ANSWERED TIME" from the agi and reduce the balance. The timer task also remove the record from the reserved table for that channel and the timer task returns to the thread pool (if any).

The above method worked fine except that if for some reason the cleanup didn't happen by timer task there are some hanging records in the reserved table. But we can write a cleanup thread to clean those records after few hours by looking at the datetime column of the reserved table.

I am happy to get some more details about your idea to get this problem resolved in future releases.

Thanks,
Thameem


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 15, 2008 6:56 pm 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
Hello thameema,

You have a very interesting approach. It is similar at some points to mine. Here is my method.

First of all, it uses a daemon that I have created with PHP. This daemon is able to receive and handle client connections through a local Unix socket connection. Why? I will explain later.

The daemon will be permanently computing and deducting money for accounts that are in use. The refresh rate has been set to 5 seconds but it can be changed.

The daemon is notified about new calls through a socket connection. So far, the daemon can understand the following commands: SHOW_COMMANDS, ECHO, PING, BYE, START, STOP, STATUS

How to use it, you simply use it the same way you would use the Asterisk Manager Interface. Only this daemon has a smaller command set.

The daemon is like a spreadsheet. It will allow new billing data to be inserted in a DB table (a memory table). Memory table types are way faster.

A typical billing data (for my testings) uses the following fields: account, channel, rate, increment.

At each cycle, the daemon will check if the global rate for each card will allow it to make it through another cycle (given their respective remaining balance). If this is not the case, I am still thinking about whether I should disconnect all the calls on the given card or do it on a first-come-first-disconnect basis. In any case, the addition of a new call will also force the daemon to check if at least 1 billing cycle can be achieved. The channel name will be used to hang and channel up when desired.

The reason of using a daemon is because if you have let's say 300 calls, the actual AGI will be executed 300 times and held in memory for the duration of the call. Also, there will be at least 300 socket connections and 300 database connections.

In my approach, there will be a small burst of the number of DB connection, socket connections and AGI usage that will be closed to the number of call per second that you will have. But after the establishment of the call, even if the DeadAGI stops working, the call will stay connected (after using a few tricks) and there will be no DB connection for each of the active call. The daemon will handle the accounting through 1 database connection.

The call setup process is extremely fast. Every time a new call will be trying to send a new set of billing data, the daemon will fork and the forked child will handle the connection without bothering the billing cycle of its parent. The lifespan of the forked daemon is extremely short. In fact, I am letting the child daemon die as soon as the main daemon gives back a clear status: Success (new call can start) or Failure (no credit, call cannot be added) and as soon as the status as been sent back to the calling application (the DIALPLAN or and AGI).

I don't know if I have explained it clearly, so please feel free to ask questions.

On an account with simultaneous usage, it does not make sense to play the balance to the caller cause the account would most likely be a wholesale account. In any case, the call duration of all caller will be constantly changing every time a new call will be added to the same card. It will also not be a good idea to play a new remaining timeout to all the callers every time a new call is added.

This whole think is currently on a development server and I am still working on it. But at it's current stage, the daemon runs and change the account balances.

Feedback, critic and suggestions are appreciated.

Cheers


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 15, 2008 7:24 pm 
Offline

Joined: Sun Jan 21, 2007 1:33 am
Posts: 22
Sounds interesting...but have few questions...

Quote:
The daemon is like a spreadsheet. It will allow new billing data to be inserted in a DB table (a memory table). Memory table types are way faster.


Do you mean to say its mysql table type or just keep it in memory?? And I assume the data is inserted every 5 seconds (everytime the daemon checks) and when will you clear the data for that card from this table?


Quote:
At each cycle, the daemon will check if the global rate for each card will allow it to make it through another cycle (given their respective remaining balance). If this is not the case, I am still thinking about whether I should disconnect all the calls on the given card or do it on a first-come-first-disconnect basis. In any case, the addition of a new call will also force the daemon to check if at least 1 billing cycle can be achieved. The channel name will be used to hang and channel up when desired.


I assume you are checking the remaining balance using this formula.
remaining balance - (sum of all inserted data for that account in memory table). Please explain.

In a situation say there are 100 cards used and 300 calls going, you have to check the balance for those 100 cards every 5 secs. Are there going to be any performance impact? And if you lose the daemon or daemon died then the data in memory will get destroyed and you also think about how to handle this.

Thanks,
Thameem


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 15, 2008 10:59 pm 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
Quote:
Do you mean to say its mysql table type or just keep it in memory?? And I assume the data is inserted every 5 seconds (everytime the daemon checks) and when will you clear the data for that card from this table?


The data for each channel will be cleared form the memory as soon as the channels is closed either by the daemon or by the callers or by asterisk. A cleaning will be done from time to time to make sure that if as channel is no longer in asterisk then it will be removed from our active channels list.

Quote:
I assume you are checking the remaining balance using this formula. remaining balance - (sum of all inserted data for that account in memory table). Please explain.


You assumed correctly. In fact, here is what the update query looks like for the moment:

Code:
UPDATE `cc_cards`, (SELECT `account`, SUM(`rate`) global_rate FROM `billing_data` GROUP BY `account`) AS rates
SET credit = credit - global_rate
WHERE cardnumber = `account`


Improvement still have to be done in the way the date is being manipulated. Instead of querying the remaining balance and calculating the sum of the rates on each card withing SQL, I am convinced that there is a way to keep some of these information in a buffer (an array for instance). The buffer can be updated at the time a new call is added or removed. So the only time the DB will access the card balance will be when it will be time to update it. This part is still a theory.

Quote:
In a situation say there are 100 cards used and 300 calls going, you have to check the balance for those 100 cards every 5 secs. Are there going to be any performance impact?


Yes. I think that it will affect performance. But I have not yet benchmarked it. The 5 seconds frequency has been decided because we wanted to see account credit changes happening at a fast pace. I believe that it would be reasonable to extend that to 60s. Even then, by doing the proper math, calculations can be done in respect to any kind of billing block (1 sec billing, 6 seconds, 60s, ...)

Quote:
And if you lose the daemon or daemon died then the data in memory will get destroyed and you also think about how to handle this.


This may seem risky, but we will have to build it reliably and we will have to rely on the stability of Linux itself. In fact, asterisk runs as daemon and uses threads. And guess what? If they fail, all the calls get lost also. With that said, I am sure that I will have to face tons of bugs and situations that I didn't foresee. For the moment, I do not see how or the daemon should fail without a reasonable explanation.

By the way, I don't mind porting this over to C++ and compile it into a binary code to make it thread safer and a lot more efficient if that is what it take.

Again, suggestions, questions, critics, comments, ... ?

Cheers


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 15, 2008 11:32 pm 
Offline

Joined: Sun Jan 21, 2007 1:33 am
Posts: 22
In my views you shouldn't update the cc_card every 5s or daemon cycle. It should get updated only end of each call by getting the real answered time from asterisk. For the daemon updates it should calculate the amount in memory and clear the channel if they don't have balance to continue.

You should also add the 'rate' column to your temp. balance table in addition to the 'increment' column so that you can calculate the rate just by querying this table. And another thing would be you may also need to check connect_charge, disconnect_charge, etc.. when you do the billing calculation.

Please let me know when do you have plans to put this in some release? Because I am having this negative balance issue with my callback functionality where most of the calls are long duration.

Thanks,
Thameem


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 16, 2008 12:39 am 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
Quote:
It should get updated only end of each call by getting the real answered time from asterisk.


I am not so sure about that. If we have to wait the end of each call before updating the balance, then we shouldn't even build anything new at all cause that's what a2billing is already doing. With some wholesale customers, there are too many long calls being made simultaneous. Some times, the server doesn't even have a break between the long calls cause they overlap. As a result, you get a negative balance. It is mainly because of that fact that I have had this idea.

Quote:
You should also add the 'rate' column to your temp. balance table in addition to the 'increment' column


There already is a rate column in my temp. table. The increment, billing block, connection charge, disconnection charge, ... will come later. It's just that I need to keep it simple first, and add the other parameters later. There is also going to be some information about progressive rates. :x

I will let you know as soon as it is ready for testing.

You said that you are still having negative balance. What version of a2billing are you running? How low does the balances go down? And what does your dialcommand_param look like in a2billing.conf?

On my call backs, the balance false to 0$ even most of the time and sometimes at the closed lowest amount that is less the the calling rate at that time. So if the rate is $0.13, than the ending balance will always be in the interval ]-0.13,+0.13[. For a call at $0.03 per minute (for both legs), the ending balance will fall within ]-0.03,+0.03[

The reason why it can go that low is because we are not charging the 1st leg for the time spent while the fellows are dialing the destination number. Customers seem to be unable to understand when we charge them for that. :lol:

Cheers


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 16, 2008 2:01 am 
Offline

Joined: Sun Jan 21, 2007 1:33 am
Posts: 22
Regarding the update here is what i was trying to explain.

You daemon should calculate the amount spent so far for that call plus amount needed to complete the call till next cycle of daemon calculation. You have to do this and find out whether each channel has enough balance to continue or disconnect the channel. (as you mentioned in the first post you don't need to disconnect all the channels from this card). You should do all these calculations without updating the real balance of customer.
The reason is, if the time calculated by your daemon interface has difference with asterisk calculated time, then the cdr will not have accurate record.


Regarding the negative balance, I still have many negative balance for the customers. I charge 0.4 credit per minute for first leg and 0.5 per minute for second leg. I have many customers who went very well below -5 credits.. which I think huge...

Here are my config snippets..

Code:
Asterisk version: 1.4.20.1
A2B version: 1.3.2 (Yellowjacket)

dialcommand_param = "|60|HRrL(%timeout%:61000:30000)"

I am using default a2b contexts in extensions.conf



I do charge for the first leg and I am using all-callback.

Thanks,
Thameem


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 16, 2008 2:24 am 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
You might want to change your dialcommand_param to ...

Code:
dialcommand_param = "|60|HRrL(%timeout%:61000:00000)"


There have been reports that the 30000 value is problematic.

I believe that v1.3.2 already contains the patch that fix the negative balance issue.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 16, 2008 2:44 am 
Offline

Joined: Sun Jan 21, 2007 1:33 am
Posts: 22
Thanks for that tip..i changed that value and i will test it..

One thing i don't understand is, that value is to give warning every z seconds as per the documentation. How will it fix the zero balance issue?

Thanks,
Thameem


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 16, 2008 2:55 am 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
Good question. I have no idea. It must be a glitch in asterisk :D. In any case, I found that a single 60 seconds warning is well enough.

Regards


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 21, 2008 5:48 pm 
Offline

Joined: Sun Jan 21, 2007 1:33 am
Posts: 22
Hi Asiby,
I have tested your tip but still getting negative balance. Do you have any other options to work around this for now?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 21, 2008 6:24 pm 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
Not yet. If you are referring to negative balance during simultaneous calls, I afraid that there is not trick that will let you work around it in a2billing. At least not until a patch is completed and submitted.

Here is the cases where you can potentially have negative balance and the error margin also varies.

- In cid-callback mode, assuming that the card does not allow simultaneous calls, the ending balance after a call has been ended due to a timeout will always be between minus n and positive n exclusive. n is the global rate for both legs. If you charge the 1st leg of the callback, the ending balance will be between 0 and positive n exclusive. Not bad. Only a few cents.

- In any calling mode (standard, cid-callback, when charging extracharge_did, ...), if you allow simultaneous calls, the balance can go negative and the ending balance can be several times the initial account balance below zero under the right conditions.

As you can see, an improvement is needed. If anyone can do something, please step forward and contribute ideas, codes, ... I have already explained my approach and even though it might seem that I am on the right track, someone else might have a better or simpler solution.

In order to illustrate a worst case scenario that leads to negative balance, you can try this:

- Create a card that allow simultaneous calls.
- Add a 5$ balance in it.
- Call your standard calling card access number and call out.
- While the 1st call in still in progress, tell 5 other people to call your access number and use the same calling card and call out. You will notice that the account balance announcement will be 5$ for each of them. And that's when the problems start.
- Make sure not to hang up any of the calls cause we want the timeout to kick in.
- When the all the calls are completed, you will notice that each caller has been able to use the whole 5$ and the account balance will become -5$ x 6 = -$30. That is for 6 callers: you and your 5 friends.

There are many calling card on the market that does allow simultaneous calls, and people take advantage of them this way.

Cheers


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 30, 2009 2:01 pm 
Offline

Joined: Fri Jan 30, 2009 12:16 pm
Posts: 2
I have an idea, that I will try to implement.
For each account there should be timer which shound contain non null value predicted time when ballance will go to zero.
Every time user starts, or ends a call this timer should be updated.
A cron job checks this value and disconects user if his time is up.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 22 posts ]  Go to page 1, 2  Next
Hosted Voice Broadcast


All times are UTC


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group