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 #include "PoolOptions.h" 00028 00029 namespace Passenger { 00030 00031 using namespace std; 00032 using namespace boost; 00033 00034 /** 00035 * A persistent pool of Applications. 00036 * 00037 * Spawning application instances, especially Ruby on Rails ones, is a very expensive operation. 00038 * Despite best efforts to make the operation less expensive (see SpawnManager), 00039 * it remains expensive compared to the cost of processing an HTTP request/response. 00040 * So, in order to solve this, some sort of caching/pooling mechanism will be required. 00041 * ApplicationPool provides this. 00042 * 00043 * Normally, one would use SpawnManager to spawn a new RoR/Rack application instance, 00044 * then use Application::connect() to create a new session with that application 00045 * instance, and then use the returned Session object to send the request and 00046 * to read the HTTP response. ApplicationPool replaces the first step with 00047 * a call to Application::get(). For example: 00048 * @code 00049 * ApplicationPool pool = some_function_which_creates_an_application_pool(); 00050 * 00051 * // Connect to the application and get the newly opened session. 00052 * Application::SessionPtr session(pool->get("/home/webapps/foo")); 00053 * 00054 * // Send the request headers and request body data. 00055 * session->sendHeaders(...); 00056 * session->sendBodyBlock(...); 00057 * // Done sending data, so we shutdown the writer stream. 00058 * session->shutdownWriter(); 00059 * 00060 * // Now read the HTTP response. 00061 * string responseData = readAllDataFromSocket(session->getStream()); 00062 * // Done reading data, so we shutdown the reader stream. 00063 * session->shutdownReader(); 00064 * 00065 * // This session has now finished, so we close the session by resetting 00066 * // the smart pointer to NULL (thereby destroying the Session object). 00067 * session.reset(); 00068 * 00069 * // We can connect to an Application multiple times. Just make sure 00070 * // the previous session is closed. 00071 * session = app->connect("/home/webapps/bar") 00072 * @endcode 00073 * 00074 * Internally, ApplicationPool::get() will keep spawned applications instances in 00075 * memory, and reuse them if possible. It wil* @throw l try to keep spawning to a minimum. 00076 * Furthermore, if an application instance hasn't been used for a while, it 00077 * will be automatically shutdown in order to save memory. Restart requests are 00078 * honored: if an application has the file 'restart.txt' in its 'tmp' folder, 00079 * then get() will shutdown existing instances of that application and spawn 00080 * a new instance (this is useful when a new version of an application has been 00081 * deployed). And finally, one can set a hard limit on the maximum number of 00082 * applications instances that may be spawned (see ApplicationPool::setMax()). 00083 * 00084 * Note that ApplicationPool is just an interface (i.e. a pure virtual class). 00085 * For concrete classes, see StandardApplicationPool and ApplicationPoolServer. 00086 * The exact pooling algorithm depends on the implementation class. 00087 * 00088 * @ingroup Support 00089 */ 00090 class ApplicationPool { 00091 public: 00092 virtual ~ApplicationPool() {}; 00093 00094 /** 00095 * Checks whether this ApplicationPool object is still connected to the 00096 * ApplicationPool server. 00097 * 00098 * If that's not the case, then one should reconnect to the ApplicationPool server. 00099 * 00100 * This method is only meaningful for instances of type ApplicationPoolServer::Client. 00101 * The default implementation always returns true. 00102 */ 00103 virtual bool connected() const { 00104 return true; 00105 } 00106 00107 /** 00108 * Open a new session with the application specified by <tt>PoolOptions.appRoot</tt>. 00109 * See the class description for ApplicationPool, as well as Application::connect(), 00110 * on how to use the returned session object. 00111 * 00112 * Internally, this method may either spawn a new application instance, or use 00113 * an existing one. 00114 * 00115 * @param options An object containing information on which application to open 00116 * a session with, as well as spawning details. Spawning details will be used 00117 * if the pool decides that spawning a new application instance is necessary. 00118 * See SpawnManager and PoolOptions for details. 00119 * @return A session object. 00120 * @throw SpawnException An attempt was made to spawn a new application instance, but that attempt failed. 00121 * @throw BusyException The application pool is too busy right now, and cannot 00122 * satisfy the request. One should either abort, or try again later. 00123 * @throw IOException Something else went wrong. 00124 * @throw thread_interrupted 00125 * @note Applications are uniquely identified with the application root 00126 * string. So although <tt>appRoot</tt> does not have to be absolute, it 00127 * should be. If one calls <tt>get("/home/foo")</tt> and 00128 * <tt>get("/home/../home/foo")</tt>, then ApplicationPool will think 00129 * they're 2 different applications, and thus will spawn 2 application instances. 00130 */ 00131 virtual Application::SessionPtr get(const PoolOptions &options) = 0; 00132 00133 /** 00134 * Convenience shortcut for calling get() with default spawn options. 00135 */ 00136 virtual Application::SessionPtr get(const string &appRoot) { 00137 return get(PoolOptions(appRoot)); 00138 } 00139 00140 /** 00141 * Clear all application instances that are currently in the pool. 00142 * 00143 * This method is used by unit tests to verify that the implementation is correct, 00144 * and thus should not be called directly. 00145 */ 00146 virtual void clear() = 0; 00147 00148 virtual void setMaxIdleTime(unsigned int seconds) = 0; 00149 00150 /** 00151 * Set a hard limit on the number of application instances that this ApplicationPool 00152 * may spawn. The exact behavior depends on the used algorithm, and is not specified by 00153 * these API docs. 00154 * 00155 * It is allowed to set a limit lower than the current number of spawned applications. 00156 */ 00157 virtual void setMax(unsigned int max) = 0; 00158 00159 /** 00160 * Get the number of active applications in the pool. 00161 * 00162 * This method exposes an implementation detail of the underlying pooling algorithm. 00163 * It is used by unit tests to verify that the implementation is correct, 00164 * and thus should not be called directly. 00165 */ 00166 virtual unsigned int getActive() const = 0; 00167 00168 /** 00169 * Get the number of active applications in the pool. 00170 * 00171 * This method exposes an implementation detail of the underlying pooling algorithm. 00172 * It is used by unit tests to verify that the implementation is correct, 00173 * and thus should not be called directly. 00174 */ 00175 virtual unsigned int getCount() const = 0; 00176 00177 /** 00178 * Set a hard limit on the number of application instances that a single application 00179 * may spawn in this ApplicationPool. The exact behavior depends on the used algorithm, 00180 * and is not specified by these API docs. 00181 * 00182 * It is allowed to set a limit lower than the current number of spawned applications. 00183 */ 00184 virtual void setMaxPerApp(unsigned int max) = 0; 00185 00186 /** 00187 * Get the process ID of the spawn server that is used. 00188 * 00189 * This method exposes an implementation detail. It is used by unit tests to verify 00190 * that the implementation is correct, and thus should not be used directly. 00191 */ 00192 virtual pid_t getSpawnServerPid() const = 0; 00193 }; 00194 00195 typedef shared_ptr<ApplicationPool> ApplicationPoolPtr; 00196 00197 }; // namespace Passenger 00198 00199 #endif /* _PASSENGER_APPLICATION_POOL_H_ */