ApplicationPool.h

00001 /*
00002  *  Phusion Passenger - http://www.modrails.com/
00003  *  Copyright (C) 2008  Phusion
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; version 2 of the License.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00017  */
00018 #ifndef _PASSENGER_APPLICATION_POOL_H_
00019 #define _PASSENGER_APPLICATION_POOL_H_
00020 
00021 #include <boost/shared_ptr.hpp>
00022 #include <sys/types.h>
00023 
00024 #include "Application.h"
00025 
00026 namespace Passenger {
00027 
00028 using namespace std;
00029 using namespace boost;
00030 
00031 /**
00032  * A persistent pool of Applications.
00033  *
00034  * Spawning Ruby on Rails application instances is a very expensive operation.
00035  * Despite best efforts to make the operation less expensive (see SpawnManager),
00036  * it remains expensive compared to the cost of processing an HTTP request/response.
00037  * So, in order to solve this, some sort of caching/pooling mechanism will be required.
00038  * ApplicationPool provides this.
00039  *
00040  * Normally, one would use SpawnManager to spawn a new RoR application instance,
00041  * then use Application::connect() to create a new session with that application
00042  * instance, and then use the returned Session object to send the request and
00043  * to read the HTTP response. ApplicationPool replaces the first step with
00044  * a call to Application::get(). For example:
00045  * @code
00046  *   ApplicationPool pool = some_function_which_creates_an_application_pool();
00047  *   
00048  *   // Connect to the application and get the newly opened session.
00049  *   Application::SessionPtr session(pool->get("/home/webapps/foo"));
00050  *   
00051  *   // Send the request headers and request body data.
00052  *   session->sendHeaders(...);
00053  *   session->sendBodyBlock(...);
00054  *   // Done sending data, so we close the writer channel.
00055  *   session->closeWriter();
00056  *
00057  *   // Now read the HTTP response.
00058  *   string responseData = readAllDataFromSocket(session->getReader());
00059  *   // Done reading data, so we close the reader channel.
00060  *   session->closeReader();
00061  *
00062  *   // This session has now finished, so we close the session by resetting
00063  *   // the smart pointer to NULL (thereby destroying the Session object).
00064  *   session.reset();
00065  *
00066  *   // We can connect to an Application multiple times. Just make sure
00067  *   // the previous session is closed.
00068  *   session = app->connect("/home/webapps/bar")
00069  * @endcode
00070  *
00071  * Internally, ApplicationPool::get() will keep spawned applications instances in
00072  * memory, and reuse them if possible. It will try to keep spawning to a minimum.
00073  * Furthermore, if an application instance hasn't been used for a while, it
00074  * will be automatically shutdown in order to save memory. Restart requests are
00075  * honored: if an application has the file 'restart.txt' in its 'tmp' folder,
00076  * then get() will shutdown existing instances of that application and spawn
00077  * a new instance (this is useful when a new version of an application has been
00078  * deployed). And finally, one can set a hard limit on the maximum number of
00079  * applications instances that may be spawned (see ApplicationPool::setMax()).
00080  *
00081  * Note that ApplicationPool is just an interface (i.e. a pure virtual class).
00082  * For concrete classes, see StandardApplicationPool and ApplicationPoolServer.
00083  * The exact pooling algorithm depends on the implementation class.
00084  *
00085  * @ingroup Support
00086  */
00087 class ApplicationPool {
00088 public:
00089         virtual ~ApplicationPool() {};
00090         
00091         /**
00092          * Open a new session with the application specified by <tt>appRoot</tt>.
00093          * See the class description for ApplicationPool, as well as Application::connect(),
00094          * on how to use the returned session object.
00095          *
00096          * Internally, this method may either spawn a new application instance, or use
00097          * an existing one.
00098          *
00099          * If <tt>lowerPrivilege</tt> is true, then any newly spawned application
00100          * instances will have lower privileges. See SpawnManager::SpawnManager()'s
00101          * description of <tt>lowerPrivilege</tt> and <tt>lowestUser</tt> for details.
00102          *
00103          * @param appRoot The application root of a RoR application, i.e. the folder that
00104          *             contains 'app/', 'public/', 'config/', etc. This must be a valid
00105          *             directory, but does not have to be an absolute path.
00106          * @param lowerPrivilege Whether to lower the application's privileges.
00107          * @param lowestUser The user to fallback to if lowering privilege fails.
00108          * @return A session object.
00109          * @throw SpawnException An attempt was made to spawn a new application instance, but that attempt failed.
00110          * @throw IOException Something else went wrong.
00111          * @note Applications are uniquely identified with the application root
00112          *       string. So although <tt>appRoot</tt> does not have to be absolute, it
00113          *       should be. If one calls <tt>get("/home/foo")</tt> and
00114          *       <tt>get("/home/../home/foo")</tt>, then ApplicationPool will think
00115          *       they're 2 different applications, and thus will spawn 2 application instances.
00116          */
00117         virtual Application::SessionPtr get(const string &appRoot, bool lowerPrivilege = true, const string &lowestUser = "nobody") = 0;
00118         
00119         /**
00120          * Clear all application instances that are currently in the pool.
00121          *
00122          * This method is used by unit tests to verify that the implementation is correct,
00123          * and thus should not be called directly.
00124          */
00125         virtual void clear() = 0;
00126         
00127         virtual void setMaxIdleTime(unsigned int seconds) = 0;
00128         
00129         /**
00130          * Set a hard limit on the number of application instances that this ApplicationPool
00131          * may spawn. The exact behavior depends on the used algorithm, and is not specified by
00132          * these API docs.
00133          *
00134          * It is allowed to set a limit lower than the current number of spawned applications.
00135          */
00136         virtual void setMax(unsigned int max) = 0;
00137         
00138         /**
00139          * Get the number of active applications in the pool.
00140          *
00141          * This method exposes an implementation detail of the underlying pooling algorithm.
00142          * It is used by unit tests to verify that the implementation is correct,
00143          * and thus should not be called directly.
00144          */
00145         virtual unsigned int getActive() const = 0;
00146         
00147         /**
00148          * Get the number of active applications in the pool.
00149          *
00150          * This method exposes an implementation detail of the underlying pooling algorithm.
00151          * It is used by unit tests to verify that the implementation is correct,
00152          * and thus should not be called directly.
00153          */
00154         virtual unsigned int getCount() const = 0;
00155         
00156         /**
00157          * Get the process ID of the spawn server that is used.
00158          *
00159          * This method exposes an implementation detail. It is used by unit tests to verify
00160          * that the implementation is correct, and thus should not be used directly.
00161          */
00162         virtual pid_t getSpawnServerPid() const = 0;
00163 };
00164 
00165 typedef shared_ptr<ApplicationPool> ApplicationPoolPtr;
00166 
00167 }; // namespace Passenger
00168 
00169 #endif /* _PASSENGER_APPLICATION_POOL_H_ */

Generated on Wed May 7 20:28:18 2008 for Passenger by  doxygen 1.5.3