I've got several issues with AGI/FastAGI 1. When an AGI script sends a command to Asterisk via stdin, why does Asterisk block and not return a result until the command is complete? Specifically, the dial command. If I send a Dial command to Asterisk, I don't get a return result until AFTER the call is HUNG UP. Not when it's ringing, not when the call is connected, but when it's DISCONNECTED. Why is that? How are you supposed to use commands like CHANNEL STATUS if you have to wait until the call is hung up, to check it's status? 2. Why do AGI scripts stay in memory until a call is complete? Is there any way to have the script terminate when a call is connected? With this scenario, you have a script for every single call in place, and that's really bad from a system resource perspective. 3. Seems that no scripting language is up to the task of FastAGI. Perl's threads aren't thread-safe with DBI and Python's aren't completely thread safe either. Don't know about Ruby, and I ain't no C programmer. What have people implemented? I also don't like the threading approach, because if something goes wrong with the script/server, you lose the ability to place ANY calls. Doug
> > > > > To: > "Asterisk Users Mailing List - Non-Commercial Discussion" > <asterisk-users@lists.digium.com> > > > I've got several issues with AGI/FastAGI > > 1. When an AGI script sends a command to Asterisk via stdin, why does Asterisk block and not return a result until the command is complete? Specifically, the dial command. If I send a Dial command to Asterisk, I don't get a return result until AFTER the call is HUNG UP. Not when it's ringing, not when the call is connected, but when it's DISCONNECTED. Why is that? How are you supposed to use commands like CHANNEL STATUS if you have to wait until the call is hung up, to check it's status? > > 2. Why do AGI scripts stay in memory until a call is complete? Is there any way to have the script terminate when a call is connected? With this scenario, you have a script for every single call in place, and that's really bad from a system resource perspective. > > 3. Seems that no scripting language is up to the task of FastAGI. Perl's threads aren't thread-safe with DBI and Python's aren't completely thread safe either. Don't know about Ruby, and I ain't no C programmer. What have people implemented? I also don't like the threading approach, because if something goes wrong with the script/server, you lose the ability to place ANY calls. > > Doug > >Hi, If you want to have a speedy system that doesn't steal to many system resources then you have to use FastAGI. That being said you have to program your FastAGI server so it's completely event driven. The way to deal with f.ex. the dial command can be to let the FastAGI set a dialplan variable and then send the control back to the dialplan which then can execute the dial command that your FastAGI did prepare. I prefer to use perl for most AGI/FastAGI solutions, the servers are started out of inittab so no forking overhead during call handling. I do normally build FastAGI servers around 'select' so the process is either working or waiting on requests. I know you will say that means that no FastAGI request are served while I wait for database responses. The workaround is to start more than one copy of your FastAGI server on different ports. Create a global variable in your dialplan , increment on each call - do a mod(4) if you have 4 servers so you can interleave the FastAGI requests between the servers. If you need persistent data for you 'after call' process then use you DB system. Let your FastAGI server write a dialplan status variable so you can retry another FastAGI server in case first one fails. It's not difficult to get 100+ call setups per second with this approach. b.r. Freddi
Hi Freddi Thanks for the reply. Neat ideas there, but a couple of issues. 1. Don't want to have to jump around between the FastAGI and the dial plan. Our plan is to have NO customer data in the dialplan, as all data will be contained within MySQL. We don't want to have to make _any_ edits to the dial plan when a new customer is added. It's a provisioning nightmare to have to do this. It also may not be a Dial() command that gets excuted for a given number dialled. It might be Meetme(), Queue() or something else. Jumping back into the dialplan and then executing the right command would be hard to maintain. It'd be helpful if Asterisk accepted something like the following, which would make it easier, but it doesn't... exten => _X.,1,AGI(//localhost/script.py) exten => _X.,2,${APP}( ${ARGS} ) What about findme/followme functionality? Are we going to have to jump backwards and forwards between the agi and the dialplan each time (all the while maintaining the last number tried in the agi) a new number is tried? We could return ALL the numbers to try at once from the AGI I guess, kinda like ${NUM1}, ${NUM2}, ${NUM3} etc. Oh YUCK! 2. How did you get around the fact that it's quite clearly documented that the perl DBI is _not_ thread safe? 3. I don't have a high enough confidence in the stability of either perl or python threading, to allow the FastAGI server to potentially receive several dozen calls, and therefore several threads each. If the FastAGI server crashes, you lost the ability to place _any_ calls. 4. Using select() system calls is a little beyond my abilities... Doug. -----Original Message----- From: Freddi Hansen [mailto:fh@danovation.dk] Sent: Tuesday, February 14, 2006 4:36 PM To: asterisk-users@lists.digium.com Subject: re:[Asterisk-Users] Multiple AGI Issues> > > > > To: > "Asterisk Users Mailing List - Non-Commercial Discussion" > <asterisk-users@lists.digium.com> > > > I've got several issues with AGI/FastAGI > > 1. When an AGI script sends a command to Asterisk via stdin, why does Asterisk block and not return a result until the command is complete? Specifically, the dial command. If I send a Dial command to Asterisk, I don't get a return result until AFTER the call is HUNG UP. Not when it's ringing, not when the call is connected, but when it's DISCONNECTED. Why is that? How are you supposed to use commands like CHANNEL STATUS if you have to wait until the call is hung up, to check it's status? > > 2. Why do AGI scripts stay in memory until a call is complete? Is there any way to have the script terminate when a call is connected? With this scenario, you have a script for every single call in place, and that's really bad from a system resource perspective. > > 3. Seems that no scripting language is up to the task of FastAGI. Perl's threads aren't thread-safe with DBI and Python's aren't completely thread safe either. Don't know about Ruby, and I ain't no C programmer. What have people implemented? I also don't like the threading approach, because if something goes wrong with the script/server, you lose the ability to place ANY calls. > > Doug > >Hi, If you want to have a speedy system that doesn't steal to many system resources then you have to use FastAGI. That being said you have to program your FastAGI server so it's completely event driven. The way to deal with f.ex. the dial command can be to let the FastAGI set a dialplan variable and then send the control back to the dialplan which then can execute the dial command that your FastAGI did prepare. I prefer to use perl for most AGI/FastAGI solutions, the servers are started out of inittab so no forking overhead during call handling. I do normally build FastAGI servers around 'select' so the process is either working or waiting on requests. I know you will say that means that no FastAGI request are served while I wait for database responses. The workaround is to start more than one copy of your FastAGI server on different ports. Create a global variable in your dialplan , increment on each call - do a mod(4) if you have 4 servers so you can interleave the FastAGI requests between the servers. If you need persistent data for you 'after call' process then use you DB system. Let your FastAGI server write a dialplan status variable so you can retry another FastAGI server in case first one fails. It's not difficult to get 100+ call setups per second with this approach. b.r. Freddi _______________________________________________ --Bandwidth and Colocation provided by Easynews.com -- Asterisk-Users mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/asterisk-users
> > Thanks for the reply. Neat ideas there, but a couple of issues. > > 1. Don't want to have to jump around between the FastAGI and the dial plan. Our plan is to have NO customer data in the dialplan, as all data will be contained within MySQL. We don't want to have to make _any_ edits to the dial plan when a new customer is added. It's a provisioning nightmare to have to do this. It also may not be a Dial() command that gets excuted for a given number dialled. It might be Meetme(), Queue() or something else. Jumping back into the dialplan and then executing the right command would be hard to maintain. It'd be helpful if Asterisk accepted something like the following, which would make it easier, but it doesn't... > > exten => _X.,1,AGI(//localhost/script.py) > exten => _X.,2,${APP}( ${ARGS} ) >We have no customer data in the dialplan, everything is done through mysql. There are 2 basic ways (at least) to use FastAGI when you dont want to have a multithreaded FastAGI server. 1. Create some 'helper' contexts in the dialplan to handle applications/actions that may take some time (like meetme,dial a.s.o.). Let the FastAGI server set some channel variables that you may need (like Destination number, which CallerID to use aso) and ofcourse the context before returning to the dialplan. 2.Use a modified version of Asterisk.pm which is build around select and nonblocking i/o that uses event driven callbacks into your application code.(yes threadsafe, it sleeps on a select call until events then create the callback. Since your not familiar with select i would recommend using method 1.> What about findme/followme functionality? Are we going to have to jump backwards and forwards between the agi and the dialplan each time (all the while maintaining the last number tried in the agi) a new number is tried? We could return ALL the numbers to try at once from the AGI I guess, kinda like ${NUM1}, ${NUM2}, ${NUM3} etc. Oh YUCK! > > 2. How did you get around the fact that it's quite clearly documented that the perl DBI is _not_ thread safe? >You can easily use a perl distro compiled without multithread enabled eventhough it shouldn't be needed. Again read up on perl IO::select. You sleep waiting for event input, execute the job and then sleep again. No multitread needed. You may issue sql request that takes 20 or 50 msec and nothing else is going on within a single server during that time so no re-entrance into unsafe DBI code. It also means other calls are not being served from that server during this period that why I pointed you to use the server interleaving.> 3. I don't have a high enough confidence in the stability of either perl or python threading, to allow the FastAGI server to potentially receive several dozen calls, and therefore several threads each. If the FastAGI server crashes, you lost the ability to place _any_ calls. > >As described above: no threading needed within the server. We have AGI servers that processes 10K+ calls per day per server ( some of the servers has 15K perl lines ) they never crash but they are started out of /etc/inittab anyway (just in case)> 4. Using select() system calls is a little beyond my abilities... > > Doug.I hope to get some time to do a cleanup on my framework for solution 2 above, it might benefit some other people that like to use agi-perl b.r. Freddi
Freddi, I started out this morning try to proof the concept of having Asterisk call an AGI script, set several variables, and then return control to the dialplan where it would execute the command. I wanted to set a number of variables in the AGI for each number to dial. The first variable would be the command to execute, for example "Dial" or "Macro". The format of this variable name would be NUM1_CMD, NUM2_CMD, ..., NUM5_CMD. Every single time I try to do anything even remotely complex in the Asterisk dial plan I hit a brick wall. This is one of the major reasons I wanted to put EVERYTHING into an AGI script. It seems to have some serious limitations that make it unusable except for the most trivial tasks. Take the variables above for example, I wanted to loop through these... exten => s,1,Set(mainLoop=1) exten => s,2,While($[${mainLoop} < 6]) exten => s,3,GotoIf($[ "${NUM$mainLoop_CMD}" = "Dial" ]?5:7) exten => s,4,Macro(CommandDial) exten => s,5,Goto(20) ... Take a look at priority 3. You'll notice I was trying to 'construct' the variable name from the loop variable. This would even work in a shell script, but it doesn't in Asterisk. Seems I have to not use a loop, and reproduce the same code each time, once for each number in the findme/followme. It sounds like you've done a lot with Asterisk.... didn't you hit brick walls every time you tried to do anything remotely complex with it? Douglas. -----Original Message----- From: Freddi Hansen [mailto:fh@danovation.dk] Sent: Tuesday, February 14, 2006 4:36 PM To: asterisk-users@lists.digium.com Subject: re:[Asterisk-Users] Multiple AGI Issues> > > > > To: > "Asterisk Users Mailing List - Non-Commercial Discussion" > <asterisk-users@lists.digium.com> > > > I've got several issues with AGI/FastAGI > > 1. When an AGI script sends a command to Asterisk via stdin, why does Asterisk block and not return a result until the command is complete? Specifically, the dial command. If I send a Dial command to Asterisk, I don't get a return result until AFTER the call is HUNG UP. Not when it's ringing, not when the call is connected, but when it's DISCONNECTED. Why is that? How are you supposed to use commands like CHANNEL STATUS if you have to wait until the call is hung up, to check it's status? > > 2. Why do AGI scripts stay in memory until a call is complete? Is there any way to have the script terminate when a call is connected? With this scenario, you have a script for every single call in place, and that's really bad from a system resource perspective. > > 3. Seems that no scripting language is up to the task of FastAGI. Perl's threads aren't thread-safe with DBI and Python's aren't completely thread safe either. Don't know about Ruby, and I ain't no C programmer. What have people implemented? I also don't like the threading approach, because if something goes wrong with the script/server, you lose the ability to place ANY calls. > > Doug > >Hi, If you want to have a speedy system that doesn't steal to many system resources then you have to use FastAGI. That being said you have to program your FastAGI server so it's completely event driven. The way to deal with f.ex. the dial command can be to let the FastAGI set a dialplan variable and then send the control back to the dialplan which then can execute the dial command that your FastAGI did prepare. I prefer to use perl for most AGI/FastAGI solutions, the servers are started out of inittab so no forking overhead during call handling. I do normally build FastAGI servers around 'select' so the process is either working or waiting on requests. I know you will say that means that no FastAGI request are served while I wait for database responses. The workaround is to start more than one copy of your FastAGI server on different ports. Create a global variable in your dialplan , increment on each call - do a mod(4) if you have 4 servers so you can interleave the FastAGI requests between the servers. If you need persistent data for you 'after call' process then use you DB system. Let your FastAGI server write a dialplan status variable so you can retry another FastAGI server in case first one fails. It's not difficult to get 100+ call setups per second with this approach. b.r. Freddi _______________________________________________ --Bandwidth and Colocation provided by Easynews.com -- Asterisk-Users mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/asterisk-users
While I've never actually tried exactly what you're doing below (constructing a variable name from strings and other variables), it looks like the variable substitution you're attempting is not being done properly. Try something like: exten => s,3,GotoIf($[ "${NUM${mainLoop}_CMD}" = "Dial" ]?5:7) Your example, I believe, will construct a variable named NUM$mainLoop_CMD without substituting the value of mainLoop into the string you're trying to build. Obviously, you have no such variable defined. - Brad -----Original Message----- From: asterisk-users-bounces@lists.digium.com [mailto:asterisk-users-bounces@lists.digium.com] On Behalf Of Douglas Garstang Sent: Wednesday, February 15, 2006 5:25 PM To: Asterisk Users Mailing List - Non-Commercial Discussion Cc: fh@danovation.dk Subject: RE: [Asterisk-Users] Multiple AGI Issues Freddi, I started out this morning try to proof the concept of having Asterisk call an AGI script, set several variables, and then return control to the dialplan where it would execute the command. I wanted to set a number of variables in the AGI for each number to dial. The first variable would be the command to execute, for example "Dial" or "Macro". The format of this variable name would be NUM1_CMD, NUM2_CMD, ..., NUM5_CMD. Every single time I try to do anything even remotely complex in the Asterisk dial plan I hit a brick wall. This is one of the major reasons I wanted to put EVERYTHING into an AGI script. It seems to have some serious limitations that make it unusable except for the most trivial tasks. Take the variables above for example, I wanted to loop through these... exten => s,1,Set(mainLoop=1) exten => s,2,While($[${mainLoop} < 6]) exten => s,3,GotoIf($[ "${NUM$mainLoop_CMD}" = "Dial" ]?5:7) exten => s,4,Macro(CommandDial) exten => s,5,Goto(20) ... Take a look at priority 3. You'll notice I was trying to 'construct' the variable name from the loop variable. This would even work in a shell script, but it doesn't in Asterisk. Seems I have to not use a loop, and reproduce the same code each time, once for each number in the findme/followme. It sounds like you've done a lot with Asterisk.... didn't you hit brick walls every time you tried to do anything remotely complex with it? Douglas. -----Original Message----- From: Freddi Hansen [mailto:fh@danovation.dk] Sent: Tuesday, February 14, 2006 4:36 PM To: asterisk-users@lists.digium.com Subject: re:[Asterisk-Users] Multiple AGI Issues> > > > > To: > "Asterisk Users Mailing List - Non-Commercial Discussion" > <asterisk-users@lists.digium.com> > > > I've got several issues with AGI/FastAGI > > 1. When an AGI script sends a command to Asterisk via stdin, why does > Asterisk block and not return a result until the command is complete? > Specifically, the dial command. If I send a Dial command to Asterisk, > I don't get a return result until AFTER the call is HUNG UP. Not when > it's ringing, not when the call is connected, but when it's > DISCONNECTED. Why is that? How are you supposed to use commands like > CHANNEL STATUS if you have to wait until the call is hung up, to check > it's status? > > 2. Why do AGI scripts stay in memory until a call is complete? Is > there any way to have the script terminate when a call is connected? > With this scenario, you have a script for every single call in place, > and that's really bad from a system resource perspective. > > 3. Seems that no scripting language is up to the task of FastAGI. > Perl's threads aren't thread-safe with DBI and Python's aren't > completely thread safe either. Don't know about Ruby, and I ain't no C > programmer. What have people implemented? I also don't like the > threading approach, because if something goes wrong with the > script/server, you lose the ability to place ANY calls. > > Doug > >Hi, If you want to have a speedy system that doesn't steal to many system resources then you have to use FastAGI. That being said you have to program your FastAGI server so it's completely event driven. The way to deal with f.ex. the dial command can be to let the FastAGI set a dialplan variable and then send the control back to the dialplan which then can execute the dial command that your FastAGI did prepare. I prefer to use perl for most AGI/FastAGI solutions, the servers are started out of inittab so no forking overhead during call handling. I do normally build FastAGI servers around 'select' so the process is either working or waiting on requests. I know you will say that means that no FastAGI request are served while I wait for database responses. The workaround is to start more than one copy of your FastAGI server on different ports. Create a global variable in your dialplan , increment on each call - do a mod(4) if you have 4 servers so you can interleave the FastAGI requests between the servers. If you need persistent data for you 'after call' process then use you DB system. Let your FastAGI server write a dialplan status variable so you can retry another FastAGI server in case first one fails. It's not difficult to get 100+ call setups per second with this approach. b.r. Freddi _______________________________________________ --Bandwidth and Colocation provided by Easynews.com -- Asterisk-Users mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/asterisk-users _______________________________________________ --Bandwidth and Colocation provided by Easynews.com -- Asterisk-Users mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/asterisk-users The contents of this e-mail are intended for the named addressee only. It contains information that may be confidential. Unless you are the named addressee or an authorized designee, you may not copy or use it, or disclose it to anyone else. If you received it in error please notify us immediately and then destroy it.