Module design tweak idea

When the time is right, I have started to construct a proposal for how the design for modules could be tweaked to be both a bit easier to write and quicker to execute.

The heart of it is recognising that modules run in two, distinct, modes:

  1. When executed during a call.
  2. When accessed from the web interface for configuration.

The separation of these two functionalities allows the former to be executed with a very lightweight start-up (which I note that some of the inbuilt AGI scripts like dialparties already do), without sacrificing much. I have no desire to get in the way of the progress of 13.0, so I’m just flagging that, at the right time, I would love to have this discussion.

We are closing out 13 and will be starting our 14 planning following Astricon. I am going to tag this post and tag a few people so it stays on the radar.

@tm1000 @xrobau @bwalters

We can also conference you in to a call if you’d like to discuss or find us in IRC.

Happy with either, just need to find a time and day that work. Which time zone are you guys in? I’m in the UK, so, at a guess, +5 to +8 from you.

I realise Astericon is on, so this is just adding some more work to this thread so it is ready when it is time to have the discussion. Here we go:

Key proposal

That modules have two classes, which provide the interface for the modules two key roles:
• ModuleCalltime.php (containing class ModuleCalltime) which contains the code for when the module is used during a call.
• Module.class.php which contains the code for configuring the module, including via ajax for the web interface in class Module.
It is worth noting that there may be some information which both classes (absolutely) need. In which case, it would be sensible to create a class ModuleBase.php which both the above classes extend.

##Configuring the module##
This remains exactly as it, using the design and structure, BMO, etc which provides such flexibility and so on. The only difference is that any calltime code should be removed from the class and put in the ModuleCalltime class, and accessed via that. Existing code such as bootstrap.php and so on remain exactly as they currently are. Overtime perhaps they could be honed to this purpose more.
##During a call##
This is where the changes are, and these can be implemented one module at a time, stepping through them one at a time
###Streamline initiation and bootstrapping###

  • Calltime bootstrap code is created that is honed to only include and load what a particular module needs, no more and no less. Each module.agi code would specify what they needed. It also loads, intantiates and calls the module, making the creation of the module agi code a relative formatily.
  • The module.agi code is then much simplified: it simply specifies the module and it’s requirements, includes bootstrap, and then call the relevant function in ModuleCalltime.

Sample code:

Note: the calltime bootstrap could be further improved to use caching. This would have to be coded explicitly, but it can be done using apc (I’m told).
This module will have to provide certain public methods:

  • setXXX If the module require database access, it will have to have a public function setDB via which the db access class can be set. setAGI is always required, others will depend on the module. So far, the following seem that they might be needed, I’m sure there are more:
    • setAGI
    • setDB
    • setAmpConf
  • handleAgiCall So that the agi code can call it. The precise nature of this call is down to the module developer

The module may also need to provide a public method for access from the configuration code. It’s up to the developer, but something like handleAjaxCall might make sense.
##Lightweight AGI##
The existing agi interface code is fantastic, and covers every eventuality. For moany modules, only a few simple functions are needed. The suggestion is that pgpagi.php becomes two classes:

  • AGIcore which contains the four or so just about always needed functions:Get the initial request
    • Get a variable
    • Set a variable
    • Set the destination
  • AGI which extends AGIcore and contains all the remaining functions.
    ##Speed analysis##
    Some previous work on the relative speed of different approaches noted that, on a particular system, a call to the superfecta module, using only the cache, averaged:
  • At present: 5.97s
  • Replace AGi with a core functions class: 5.92s
    Using the approach above, the module execution speed is 1.9s.

Module call time is not needed. The modules autoload with bmo. You chose what is loaded. We don’t need yet another class

Needed? no, the system runs as is.

On the other hand, in my opinion it would:

  • Separate the two core functionalities of the module (being used in a call and being configured)
  • Allow BMO to work magnificently as it does in the configuration actions allowing all the module cross checking, integration etc to happen smoothly.
  • Allow the call-time execution to focus purely on the things to do with execution during call time.
  • Mean that module loading (which must be done during call time because there is no default cache system as it is running CLI) can be streamlined for execution purposes. When you only want to load one module to execute it, it could be argued that BMO is somewhat more than is strictly needed. You’ll note from the code that the proposal integrates with the BMO framework where needed.

You can do this without proposing a completely new spec “class”. Speed improvements can be done in BMO utilizing the auto loading mechanism. You are proposing a new spec because no auto loader exists yet for BMO. So you are making speed improvements by re-writing/re-structuring and adding yet another bootstrap interface to maintain. The reason I argue this is because it adds yet another layer of complexity to FreePBX when freepbx is already complex enough. BMO can manage the call flow as well. Furthermore there aren’t many modules that even use or do AGI and those can do it like they always have, through BMO, only loading themselves. and any other assets they need. Are YOU going to maintain these extra classes and the documentation and the code updating?

I am not negating your ideas for speed improvements. Only negating additional classes that aren’t needed.

I assure you that we don’t need a whole other class architecture for AGI calls.

I fail to see why. BMO only loads one module. With your proposed spec we now have to remember where everything is at. For a “proposed” speed gain of 4 seconds (was this done on a Pi?)

Take a look at composer for how autoloading should work (and where FreePBX is headed). They don’t have multiple “bootstrap/autoloader” files that you pick and choose from. You just include autoload.php once. That’s it. That’s what FreePBX needs. Not multiple autoloaders/class constructs.

Interesting … I’ve tried to think through your various comments, and I’ve tried to separate the various point I think you are making.

Underlying everything, it seems there is a big concern that the one thing that must be avoided is making things more complicated. I agree.

It seems also that you are dubious of my comments about the level of speeding up achievable. Yes, it was done on a pi. The point isn’t the 4 seconds; the point is the 65% improvement in speed for module start up. Whether you are using a pi, or a larger machine handling a very complex pbx, I would suggest this gain is worth considering.

###Design Philosophy###
It seems to me that you feel that seeing a module as a single entitiy is the route to simplicity, I am suggesting that abstratcing the ‘calltime’ functions from the ‘configuration’ functions of a module will in the end make things simpler: yes, more classes, but each class less messy. It’s a design choice, and, at one level it doesn’t matter.

I’ve probably missed something obvious here, but ‘composer’ is a rather broadly used term. Could you clarify which composer you mean? I’ll happily look.

This is relatively peripheral: all I have done is to split the existing code between two classes so that modules that only need the AGI basics can use them without needing to load all the bits they don’t need. Not worth fighting over, and I wont.

Actually, that’s not how all the modules do it. For example, dialparties.php (which is used to implement the ring groups module) skips BMO completely and just uses phpagi.php.

###bootstrp and BMO###

If that were really the case, then we wouldn’t be having this conversation. The framework I’ve proposed only loads one module and AGI (obviously it can skip loading AGI for modules which are run at calltime and don’t use AGI, if such a module exists). It takes 65% less time than bootstrp.php, BMO and a single module load. Clearly other things are going on.

Now, I think your point is that we should have a serious look at bootstrap.php and try to get it to the point where it really is only loading what is needed. If so, I’m game. I proposed the route I did because it created a way of constructing a way of doing this without the danger of messing up the complex interactions that clearly are needed for some of the modules in configuring mode. If you can point to a module that needs these complex interactions in calltime, I’d be very happy to look and learn.

Am I happy to update the documentation to reflect what is implemented: Yes.

Can I promise to maintain code in perpetuity? No.

However, given that all I am actually proposing is:

  • The current AGI code is (unchanged) split between two classes. No more maintenance than now, but,. as I’ve said above, if this is not acceptable, so be it.
  • The code in a module goes from two files (module.agi and Module.class.php) to three (module.agi, ModuleCalltime.php and Module.class.php). Again, no increase in code, just in abstraction, so I’m not sure that the question applies here.
  • An additional bootstrap file. This would need to be maintained in line with future changes in freepbx. Yes, I’m happy to help. Can I promise that I will never have a job which gets in the way? No. Am I a willing volunteer? Yes.

I’m taking another look at this. With JUST freepbx loading all of the core/basic components I am seeing a load time of below:

[root@localhost ~]# time php speed.php
real	0m0.181s
user	0m0.147s
sys	0m0.022s

This is less than a second. Can you give me an example of speed degradation without it being an AGI?

First, sorry for the late reply - I have been away. I thought I had sent a reply apologising for my absence but it doesn’t seem to have got through.

To answer your question: all the work I have done has been on modules being run during call time, ie via AGI, so I’m afraid I can’t. In fact, the specific concern I am raising is the slow start of modules when called via AGI,. ie during the call processing sequence. (I’m not at all concerned how long modules take to instantiate in other, non time critical, situations. Obviously my web server is rather slower than if I used a more powerful device, I’m not bothered by that.) The call processing speed matters because it represents a delay between when the call comes in and when a ‘handset’ eventually rings.

As I understand it, this, by definition, is invoked via AGI, so that is what I have been looking at.

The times you calculated towards the end of provide an idea of what I’m talking about.

I am running the same tests and now getting .1 of a second. Loading an AGI would be the same speed. I am sorry but I can’t see that any speed improvements need to be worked on for normal hardware. We don’t officially support the Ras Pi for many reasons. Hardward being one of them

That’s interesting. The inquisitive side of me wonders if anything else has changed, but I’m sure that you will have thought of that. If that really is the case then you are probably right to ignore the motivation: it’s only home based users using low grade hardware who are affected.
Obviously, I am of the view that the code would be easier to understand, develop and maintain if a the design reflected the two different modes it operates in more clearly; you are not, no worries. Let’s drop the idea.