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_ */