ApplicationPool.h

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

Generated on Fri Jan 23 08:28:57 2009 for Passenger by  doxygen 1.4.7