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