Abstract: The ExecuteAndWait pattern allows web applications to run long-lived code in the background while showing the web user a progress meter. This pattern prevents the web user and HTTP request from timing out when the code takes more than 30 seconds or so. Until now, PHP has not been able to easily achieve this pattern. This article describes how to achieve this pattern with PHP.
Requirements
The ExecuteAndWait pattern for PHP requires a FastCGI implementation such as may be used with LigHTTPd. Additionally, PHP must be built with support for POSIX and PCNTL functions. Because of these requirements, this pattern is known to not work with Microsoft Windows. The implementation may or may not work with Apache using mod_php. Windows and Apache mod_php could be extended with a custom module for PHP to provide a wrapper for such functionality, if the need arises.
The ExecuteAndWait pattern requires a database table for the child to communicate the results to the parent. This implementation is tested and in use with MySQL. The following SQL statement will create the necessary table for MySQL:
|
Implementation
The first requirement of the ExecuteAndWait pattern is a method for PHP to spawn code to the background. This is achieved with the Daemon class. The Daemon class causes a literal fork of the PHP code, allowing a parent and child to continue as separate processes. These separate processes inherit all available variables at the time of the fork. Additionally, the child inherits the open resources of the parent. This is most certainly bad and will cause undefined behavior. An example is a database connection. Most likely, the parent will display a message to the web user stating the processing is occurring and then exit. At the point the parent exits, the child's database connection is closed! This is probably not what the child process expected. Therefore, prior to using the Daemon or ExecuteAndWait classes, it is imperative to close all resources and re-open them after using the Daemon and/or ExecuteAndWait classes. Also, the child process should set the execution timeout to a high value. If this is not done, the child will timeout according to the PHP.INI's configured timeout value.
Building upon the Daemon class is the ExecuteAndWait class. The ExecuteAndWait class uses a database table to create a record which is then used by the parent to query the status of the child and is used by the child to report the status to the parent.
Upon initially creating the ExecuteAndWait class and using the run() method, the database ID is created, the child is created, and the parent issues a web page with a timed reload. At this point, the child is running and the web user will request the page again in the configured time delay. When the web user requests the page again, the ID is searched and its status is checked. If it's not complete, the onRefresh() method is called to generate another time delayed web page. If the child is complete, the onDone() method is called to perform the final work of displaying the results to the web user.
Extending
A few things could be done to further the abilities of this implementation. First, if a PHP error is caught, it could log the fact for the child process. Second, if a signal is caught, it could be logged for the child process.
This is an initial implementation and time permitting, will be updated as additional changes are made.
Source Code
The source code was written such that both PHP 4 and PHP 5 are supported.
- Daemon.inc.php - Contains the Daemon and ExecuteAndWait classes. The database layer is written with the ADODB library. Using the Daemon class does not require database access, but ExecuteAndWait does. One will probably have to 'rework' the database access for their own usage.
- daemon_test.php - Contains a sample class MyTest that extends the ExecuteAndWait class, showing a sample of usage.
Conclusion
The ExecuteAndWait pattern is a frequently needed item in Enterprise web applications. This functionality is missing from PHP. By utilizing these classes, we realize this missing functionality and help bring PHP one step closer to other languages such as Java for Enterprise web application programming.
References
LigHTTPd
http://www.lighttpd.net/
MySQL
http://www.mysql.com/
ADODB
http://adodb.sf.net/
About the Author
Joseph Benden, Sr. is the owner of Thralling Penguin LLC. Thralling Penguin designs, develops, and extends software technologies for the most demanding business applications.