Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 616 lines (518 sloc) 21.662 kB
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
1 = ApplicationPool algorithm
2
3
4 == Introduction
5
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application co…
FooBarWidget authored
6 For efficiency reasons, Passenger keeps a pool spawned Rails/Ruby applications.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
7 Please read the C++ API documentation for the ApplicationPool class for a full
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
8 introduction. This document describes an algorithm for managing the pool, in a
9 high-level way.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
10
11 The algorithm should strive to keep spawning to a minimum.
12
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
13
14 == Definitions
15
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application co…
FooBarWidget authored
16 === Vocabulary
17
18 - "Application root":
19 The toplevel directory in which an application is contained. For Rails
20 application, this is the same as RAILS_ROOT, i.e. the directory that contains
21 "app/", "public/", etc. For a Rack application, this is the directory that
22 contains "config.ru".
23
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
24 - "Active application process":
25 An application process that has more than 0 sessions.
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application co…
FooBarWidget authored
26
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
27 === Types
28
29 Most of the types that we use in this document are pretty standard. But we
30 explicitly define some special types:
31
32 - list<SomeType>
33 A doubly linked list which contains elements of type SomeType. It supports
34 all the usual list operations that one can expect from a linked list, like
35 add_to_back(), etc.
36
9c961e4 @FooBarWidget Some documentation updates.
FooBarWidget authored
37 We assume that operations that insert an element into the list return an
38 iterator object. An iterator object is an opaque object which represents a
39 specific position in the list; it probably contains the links to the previous
40 and the next iterator, as well as a reference to the actual list element,
41 depending on the list implementation.
42
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
43 The following operations deserve special mention:
44 * remove(iterator)
9c961e4 @FooBarWidget Some documentation updates.
FooBarWidget authored
45 Removes the specified element from the list, as represented by the given
46 iterator. This operation can be done in O(1) time.
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
47
48 * move_to_front(iterator)
9c961e4 @FooBarWidget Some documentation updates.
FooBarWidget authored
49 Moves the specified element - as represented by the given iterator - to
50 the front of the list. This operation can be done in O(1) time.
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
51
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
52 - Group
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application co…
FooBarWidget authored
53 A compound type (class) which contains information about an application root,
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
54 such as the application processes that have been spawned for this application
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application co…
FooBarWidget authored
55 root.
56
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
57 A Group has the following members:
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
58 * name (string):
59 This group's key in the _groups_ map of the application pool.
60
61 * app_root (string):
62 This group's application root. Note that it is *not* guaranteed that all
63 ProcessInfo objects in _processes_ have the same application root.
64
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
65 * processes (list<ProcessInfo>):
66 A list of ProcessInfo objects.
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application co…
FooBarWidget authored
67
68 Invariant:
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
69 processes is non-empty.
70 for all 0 <= i < processes.size() - 1:
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
71 processes[i].group_name == name
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
72 if processes[i].process is active:
73 processes[i + 1].process is active
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application co…
FooBarWidget authored
74
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
75 * size (unsigned integer):
76 The number of items in _processes_.
77 Invariant:
78 if !detached:
79 size == processes.size()
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
80
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
81 * max_requests (unsigned integer):
82 The maximum number of requests that each application process in
83 this group may process. After having processed this
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
84 many requests, the application process will be shut down.
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
85 A value of 0 indicates that there is no maximum.
a1039bf @FooBarWidget Get rid of app_instance_count, that information is now stored in Domain.
FooBarWidget authored
86
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
87 * min_processes (unsigned integer):
88 The minimum number of processes that the cleaner thread should keep in
89 this group. Defaults to 0.
90
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
91 * spawning (boolean): Whether a background thread is currently spawning
92 a new process for this group.
93
94 * spawner_thread: A handle to the background thread that is currently
95 spawning a new process. Only valid if _spawning_ is true.
96
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
97 * detached (boolean): If true, then it indicates that this Group is
e55d098 @FooBarWidget Fix some errors in the application pool algorithm description.
FooBarWidget authored
98 no longer accessible via _groups_.
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
99 Set to false by the constructor.
100 Invariant:
e55d098 @FooBarWidget Fix some errors in the application pool algorithm description.
FooBarWidget authored
101 (detached) == (This Group is accessible via _groups_.)
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
102 if detached:
103 for all process_info objects p that have once been in this.processes:
104 p.detached
105
550e0b1 @FooBarWidget Track environment name in ApplicationPool.
FooBarWidget authored
106 * environment (string): Does nothing. Data is stored in memory for analytics
107 purposes.
108
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
109 - ProcessInfo
110 A compound type (class) which contains a reference to an application process
111 object, as well as various metadata, such as iterators for various linked
112 lists. These iterators make it possible to perform actions on the linked
113 lists in O(1) time.
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
114
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
115 A ProcessInfo has the following members:
116 * process - A process object, representing an application process.
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
117 * group_name (string) - The name of the group that this ProcessInfo belongs
118 to.
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
119 * identifier (string) - A key that uniquely identifies this ProcessInfo in
120 this application pool. This key allows external processes to refer to a
121 specific ProcessInfo object without knowing its memory pointer. It's set
122 to a random string by ProcessInfo's constructor.
f569229 @FooBarWidget Fix some inconsistencies in the application pool algorithm description.
FooBarWidget authored
123 * start_time (timestamp with milisecond resolution) - The time at which this
d05bd9b @FooBarWidget Update the application pool algorithm description.
FooBarWidget authored
124 application process was started. It's set to the current time by the
125 constructor.
eb65c91 @FooBarWidget Display additional information in passenger-status: the number of req…
FooBarWidget authored
126 * processed_requests (integer) - The number of requests processed by this
d05bd9b @FooBarWidget Update the application pool algorithm description.
FooBarWidget authored
127 application instance so far. Set to 0 by the constructor.
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
128 * last_used (time) - The last time a session for this application process
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
129 was opened or closed.
130 * sessions (integer) - The number of open sessions for this application
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
131 process. It's set to 0 by the constructor.
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
132 Invariant:
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
133 (sessions == 0 && !detached) == (This ProcessInfo is in inactive_apps.)
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
134 * iterator - The iterator for this ProcessInfo in the linked list
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
135 groups[process_info.group_name].processes
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
136 * ia_iterator - The iterator for this ProcessInfo in the linked list
137 inactive_apps. This iterator is only valid if this ProcessInfo really is
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
138 in that list.
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
139 * detached (boolean) - If true, then it indicates that this ProcessInfo is
e55d098 @FooBarWidget Fix some errors in the application pool algorithm description.
FooBarWidget authored
140 no longer accessible via _groups_; this implies that it's no longer
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
141 contained in its associated Group's _processes_ member, a), and that
142 _iterator_ and _ia_iterator_ are no longer valid.
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
143 Set to false by the constructor.
144 Invariant:
e55d098 @FooBarWidget Fix some errors in the application pool algorithm description.
FooBarWidget authored
145 (detached) == (This ProcessInfo is accessible via _groups_.)
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
146
4dacc10 @FooBarWidget Various refactorings and improvements.
FooBarWidget authored
147 - PoolOptions
148 A structure containing additional information used by the spawn manager's
149 spawning process, as well as by the get() function.
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
150
0bc257a @FooBarWidget Fix a bug which prevents ApplicationSpawner/FrameworkSpawner from bei…
FooBarWidget authored
151 A PoolOptions has at least the following members:
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
152 * app_group_name (string) - A name which is used to group application
153 processes together.
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
154 * max_requests (unsigned integer) - The maximum number of requests that the
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
155 application process may process. After having processed this many requests,
156 the application process will be shut down. A value of 0 indicates that there
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
157 is no maximum.
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
158 * min_processes (unsigned integer) - The minimum number of processes for the
159 current group that the cleaner thread should keep around.
4dacc10 @FooBarWidget Various refactorings and improvements.
FooBarWidget authored
160 * use_global_queue (boolean) - Whether to use a global queue for all
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
161 application processes, or a queue that's private to the application process.
4dacc10 @FooBarWidget Various refactorings and improvements.
FooBarWidget authored
162 The users guide explains this feature in more detail.
0bc257a @FooBarWidget Fix a bug which prevents ApplicationSpawner/FrameworkSpawner from bei…
FooBarWidget authored
163 * restart_dir (string) - The directory in which the algorithm should look for
164 restart.txt and always_restart.txt. The existance and modification times of
165 these files tell the algorithm whether an application should be restarted.
550e0b1 @FooBarWidget Track environment name in ApplicationPool.
FooBarWidget authored
166 * environment (string) - The environment (RAILS_ENV/RACK_ENV) in which the app
167 should run.
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
168
0e8110d @FooBarWidget Explicitly document locking in the ApplicationPool algorithm doucment…
FooBarWidget authored
169 === Special functions
170
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
171 - spawn(app_root, options)
172 Spawns a new application process at the given application root with the given
173 spawn options. Throws an exception if something went wrong. This function is
174 thread-safe. Note that application process initialization can take an arbitrary
175 amount of time.
0e8110d @FooBarWidget Explicitly document locking in the ApplicationPool algorithm doucment…
FooBarWidget authored
176
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
177 === Instance variables
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
178
179 The algorithm requires the following instance variables for storing state
180 information:
181
0e8110d @FooBarWidget Explicitly document locking in the ApplicationPool algorithm doucment…
FooBarWidget authored
182 - lock: mutex
183 This lock is used for implementing thread-safetiness. We assume that it
184 is non-recursive, i.e. if a thread locks a mutex that it has already locked,
185 then it will result in a deadlock.
186
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
187 - groups: map[string => Group]
188 Maps an application root to its Group object. This map contains all
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
189 application processes in the pool.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
190
a1039bf @FooBarWidget Get rid of app_instance_count, that information is now stored in Domain.
FooBarWidget authored
191 Invariant:
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
192 for all values g in groups:
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
193 !g.detached
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
194 g.size <= count
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
195 for all i in g.processes:
196 !i.detached
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
197 (sum of all g.size in groups) == count
a1039bf @FooBarWidget Get rid of app_instance_count, that information is now stored in Domain.
FooBarWidget authored
198
996ada0 @FooBarWidget Add some documentation
FooBarWidget authored
199 - max: integer
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
200 The maximum number of ProcessInfo objects that may exist in the pool.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
201
7423478 @FooBarWidget Apply Jochen Tuchbreiter's RailsMaxInstancesPerApp patch. Doesn't pas…
FooBarWidget authored
202 - max_per_app: integer
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
203 The maximum number of ProcessInfo objects that may be simultaneously alive
204 for a single Group.
7423478 @FooBarWidget Apply Jochen Tuchbreiter's RailsMaxInstancesPerApp patch. Doesn't pas…
FooBarWidget authored
205
996ada0 @FooBarWidget Add some documentation
FooBarWidget authored
206 - count: integer
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
207 The current number of ProcessInfo objects in the pool.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
208 Since 'max' can be set dynamically during the life time of an application
209 pool, 'count > max' is possible.
210
996ada0 @FooBarWidget Add some documentation
FooBarWidget authored
211 - active: integer
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
212 The number of application processes in the pool that are active.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
213 Invariant:
214 active <= count
215
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
216 - inactive_apps: list<ProcessInfo>
217 A linked list of ProcessInfo objects. All application processes in this list
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
218 are inactive.
219
220 Invariant:
221 inactive_apps.size() == count - active
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
222 for all x in inactive_apps:
e55d098 @FooBarWidget Fix some errors in the application pool algorithm description.
FooBarWidget authored
223 x can be accessed from _groups_.
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
224 x.sessions == 0
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
225
64a39c0 @FooBarWidget Implement global queueing for ApplicationPool, to fight long-running …
FooBarWidget authored
226 - waiting_on_global_queue: integer
227 If global queuing mode is enabled, then when get() is waiting for a backend
228 process to become idle, this variable will be incremented. When get() is done
229 waiting, this variable will be decremented.
230
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
231
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application co…
FooBarWidget authored
232 == Class relations
233
234 Here's an UML diagram in ASCII art:
235
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
236 [ProcessInfo] 1..* --------+
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application co…
FooBarWidget authored
237 |
238 |
239
240 1
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
241 [ApplicationPool] [Group]
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application co…
FooBarWidget authored
242 1 0..*
243
244 | |
245 +-------------------+
246
247
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
248 == Algorithm in pseudo code
996ada0 @FooBarWidget Add some documentation
FooBarWidget authored
249
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
250 # Thread-safetiness notes:
251 # - All wait commands are to unlock the lock during waiting.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
252
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
253
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
254 # Connect to an existing application process, or spawn a new application process
255 # and connect to that if necessary.
256 # 'app_root' refers to an application root.
257 # 'options' is an object of type 'PoolOptions', which contains additional
258 # information which may be relevant for spawning.
b4ef02e @FooBarWidget Session close callback should accept a const Session pointer.
FooBarWidget authored
259 #
260 # Returns a Session object, representing a single HTTP request/response pair.
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
261 function get(app_root, options):
542ea8c @FooBarWidget - Add invariant checks into the ApplicationPool code so that we can d…
FooBarWidget authored
262 MAX_ATTEMPTS = 10
d0d8a84 @FooBarWidget ApplicationPool.get() now times out based on time instead of number o…
FooBarWidget authored
263 attempt = 0
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
264 while (true):
265 attempt++
266 lock.synchronize:
dd80e55 @FooBarWidget Update ApplicationPool algorithm description: rename spawn_or_use_exi…
FooBarWidget authored
267 process_info, group = checkout_without_lock(app_root, options)
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
268 try:
269 return process_info.process.connect()
270 on exception:
271 # The app process seems to have crashed.
272 # So we remove this process from our data
273 # structures.
274 lock.synchronize:
275 detach_without_lock(process_info.identifier)
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
276 process_info.sessions--
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
277 if (attempt == MAX_ATTEMPTS):
278 propagate exception
279
280
dd80e55 @FooBarWidget Update ApplicationPool algorithm description: rename spawn_or_use_exi…
FooBarWidget authored
281 # Detach the process with the given identifier from the pool's data structures.
282 function detach(identifier):
283 lock.synchronize:
284 return detach_without_lock(identifier)
285
286
287 # Checkout a process from the application pool and mark it as being used.
288 # If there's no appropriate process in the pool, or if there are not
289 # enough processes, then one will be spawned.
290 #
291 # Returns a pair of [ProcessInfo, Group].
292 # All exceptions that occur are propagated.
293 private function checkout_without_lock(app_root, options):
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
294 group = groups[options.app_group_name]
ab0db05 @FooBarWidget Fixed the restart bug. :)
FooBarWidget authored
295
0bc257a @FooBarWidget Fix a bug which prevents ApplicationSpawner/FrameworkSpawner from bei…
FooBarWidget authored
296 if needs_restart(app_root, options):
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
297 Tell spawn server to reload code for options.app_group_name.
d2edc1e @FooBarWidget Fix some consistency in the application pool algorithm description.
FooBarWidget authored
298 if (group != null):
a4e53cb @FooBarWidget Make the ApplicationPool code DRYer by moving some code into functions
FooBarWidget authored
299 detach_group_without_lock(group)
d2edc1e @FooBarWidget Fix some consistency in the application pool algorithm description.
FooBarWidget authored
300 group = null
ab0db05 @FooBarWidget Fixed the restart bug. :)
FooBarWidget authored
301
d2edc1e @FooBarWidget Fix some consistency in the application pool algorithm description.
FooBarWidget authored
302 if (group != null):
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
303 # There are existing processes for this app group.
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
304 processes = group.processes
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application co…
FooBarWidget authored
305
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
306 if (processes.front.sessions == 0):
307 # There is an inactive process, so we use it.
308 process_info = processes.front
309 processes.move_to_back(process_info.iterator)
310 inactive_apps.remove(process_info.ia_iterator)
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
311 mutate_max(active + 1)
312 else:
313 # All existing processes are active. We either use
314 # one of them now or we wait until one of them becomes
315 # available. And, if we're allowed to, we spawn an
316 # extra process in the background.
c6288f7 @FooBarWidget Make sure that asynchronous spawning respects the usual limiting rules.
FooBarWidget authored
317 if spawning_allowed(group, options) and !group.spawning:
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
318 spawn_in_background(group, options)
d8d8cc9 @FooBarWidget Some code refactoring.
FooBarWidget authored
319 process_info = select_process(processes, options)
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
320 if (process_info == null):
64a39c0 @FooBarWidget Implement global queueing for ApplicationPool, to fight long-running …
FooBarWidget authored
321 goto beginning of function
996ada0 @FooBarWidget Add some documentation
FooBarWidget authored
322 else:
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
323 # There are no processes for this app group.
f50d427 @FooBarWidget Fix a possible invariant violation in the application pool algorithm.
FooBarWidget authored
324 if (active >= max):
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
325 # Looks like the pool is full and all processes are busy.
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
326 # Wait until the pool appears to have changed in such a
327 # way that we can spawn a new app group, and restart
328 # this function.
329 new_app_group_creatable.wait
9848353 @FooBarWidget Fix a typo.
FooBarWidget authored
330 goto beginning of function
d94c6c7 @FooBarWidget Fix ApplicationPool bug: don't spawn more groups if count > max.
FooBarWidget authored
331 elsif count >= max:
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
332 # The pool is full, and not all processes are busy, but
333 # we're in a though situation nevertheless: there are
334 # several processes which are inactive, and none of them
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
335 # belong to our current app group, so we must kill one
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
336 # of them in order to free a spot in the pool. But which
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
337 # one do we kill? We want to minimize spawning.
338 #
339 # It's probably a good idea to keep some kind of
340 # statistics in order to decide this. We want the
341 # application root that gets the least traffic to be
342 # killed. But for now, we kill a random application
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
343 # process.
344 process_info = inactive_apps.pop_front
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback…
FooBarWidget authored
345 process_info.detached = true
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
346 group = groups[process_info.group_name]
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
347 processes = group.processes
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
348 processes.remove(process_info.iterator)
349 if processes.empty():
a4e53cb @FooBarWidget Make the ApplicationPool code DRYer by moving some code into functions
FooBarWidget authored
350 detach_group_without_lock(group)
7423478 @FooBarWidget Apply Jochen Tuchbreiter's RailsMaxInstancesPerApp patch. Doesn't pas…
FooBarWidget authored
351 else:
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
352 group.size--
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
353 mutate_count(count - 1)
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
354 process_info = new ProcessInfo
d05bd9b @FooBarWidget Update the application pool algorithm description.
FooBarWidget authored
355 process_info.process = spawn(app_root, options)
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
356 process_info.group_name = options.app_group_name
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
357 group = new Group
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
358 group.name = options.app_group_name
359 group.app_root = app_root
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
360 group.size = 1
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
361 groups[options.app_group_name] = group
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
362 iterator = group.processes.add_to_back(process_info)
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
363 process_info.iterator = iterator
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
364 mutate_count(count + 1)
365 mutate_active(active + 1)
c6288f7 @FooBarWidget Make sure that asynchronous spawning respects the usual limiting rules.
FooBarWidget authored
366 if (options.min_processes > 1) and spawning_allowed(group, options):
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
367 spawn_in_background(group, options)
ad57387 @FooBarWidget Refactor some code.
FooBarWidget authored
368
4448a7e @FooBarWidget ApplicationPool: synchronize group info with pool options on every re…
FooBarWidget authored
369 group.max_requests = options.max_requests
370 group.min_processes = options.min_processes
371 group.environment = options.environment
372
ad57387 @FooBarWidget Refactor some code.
FooBarWidget authored
373 process_info.last_used = current_time()
374 process_info.sessions++
db2c83a @FooBarWidget Minor code changes.
FooBarWidget authored
375
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename…
FooBarWidget authored
376 return [process_info, group]
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
377
378
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
379 private function mutate_active(value):
380 if (value < active):
381 new_app_group_creatable.notify_all
382 global_queue_position_became_available.notify_all
383 active = value
384
385 private function mutate_count(value):
386 # No point in notifying new_app_group_creatable here;
387 # if _count_ is being increased then that means the pool
388 # isn't full, and nobody is waiting on
389 # new_app_group_creatable.
390 global_queue_position_became_available.notify_all
391 count = value
392
393 private function mutate_max(value):
394 if (value > max):
395 new_app_group_creatable.notify_all
396 # We will want any code waiting on the global queue
397 # to go ahead and spawn another process.
398 global_queue_position_became_available.notify_all
399 max = value
400
401
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
402 private function needs_restart(app_root, options):
0bc257a @FooBarWidget Fix a bug which prevents ApplicationSpawner/FrameworkSpawner from bei…
FooBarWidget authored
403 if (options.restart_dir is not set):
404 restart_dir = app_root + "/tmp"
405 else if (options.restart_dir is an absolute path):
406 restart_dir = options.restart_dir
407 else:
408 restart_dir = app_root + "/" + options.restart_dir
409
410 return (file_exists("$restart_dir/always_restart.txt")) or
411 (we haven't seen "$restart_dir/restart.txt" before) or
412 ("$restart_dir/restart.txt" changed since the last time we checked)
090e459 @FooBarWidget Improve ApplicationPool algorithm: better support for restarts, fix a…
FooBarWidget authored
413
414
c6288f7 @FooBarWidget Make sure that asynchronous spawning respects the usual limiting rules.
FooBarWidget authored
415 private function spawning_allowed(group, options):
416 return ( count < max ) and
417 ( (max_per_app == 0) or (group.size < max_per_app) )
418
419
a4e53cb @FooBarWidget Make the ApplicationPool code DRYer by moving some code into functions
FooBarWidget authored
420 # Precondition: !group.detached
421 private function detach_group_without_lock(group):
422 for all process_info in group.processes:
423 if (process_info.sessions == 0):
424 inactive_apps.remove(process_info.ia_iterator)
425 else:
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
426 mutate_active(active - 1)
a4e53cb @FooBarWidget Make the ApplicationPool code DRYer by moving some code into functions
FooBarWidget authored
427 group.processes.remove(process_info.iterator)
428 process_info.detached = true
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
429 mutate_count(count - 1)
430 if (group.spawning):
431 group.spawner_thread.interrupt_and_join
432 group.spawner_thread = null
433 group.spawning = false
a4e53cb @FooBarWidget Make the ApplicationPool code DRYer by moving some code into functions
FooBarWidget authored
434 group.detached = true
435 groups.remove(options.app_group_name)
436
437
d8d8cc9 @FooBarWidget Some code refactoring.
FooBarWidget authored
438 private function select_process(processes, options):
439 if options.use_global_queue:
440 # So we wait until _active_ has changed, then
441 # we restart this function and try again.
442 waiting_on_global_queue++
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
443 global_queue_position_became_available.wait
d8d8cc9 @FooBarWidget Some code refactoring.
FooBarWidget authored
444 waiting_on_global_queue--
445 return null
446 else:
447 # So we connect to an already active process.
448 # This connection will be put into that
449 # process's private queue.
450 process_info = an element in _processes_ with the smallest _session_ value
451 processes.move_to_back(process_info.iterator)
452 return process_info
453
454
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
455 # Preconditions:
456 # !group.detached
457 # !group.spawning
458 private function spawn_in_background(group, options):
459 group.spawning = true
460 group.spawner_thread = new thread(spawner_thread_callback,
461 with these arguments to the thread function:
462 group, options)
463
464
465 private function spawner_thread_callback(group, options):
466 Ignore thread interruptions in this function
467 while true:
468 try:
469 Allow thread interruptions in this block
470 process = spawn(app_root, options)
471 on thread interruption:
472 lock.synchronize:
473 group.spawning = false
474 group.spawner_thread = null
475 return
476 on exception:
477 lock.synchronize:
478 if (!group.detached):
479 group.spawning = false
480 group.spawner_thread = null
06514c5 @FooBarWidget Move a comment
FooBarWidget authored
481 # We want to report the error to the browser
482 # but there's no way to do this in this thread, so
483 # we just remove the entire group and have the next
484 # get() call spawn the process and display the
485 # error.
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
486 remove_group_without_lock(group)
487 return
488
489 lock.synchronize:
490 if (group.detached):
491 return
492 else:
493 process_info = new ProcessInfo
494 process_info.process = process
495 process_info.group_name = options.app_group_name
496 process_info.iterator = group.processes.add_to_front(process_info)
497 process_info.ia_iterator = inactive_apps.add_to_back(process_info)
498 group.size++
499 mutate_count(count + 1)
c6288f7 @FooBarWidget Make sure that asynchronous spawning respects the usual limiting rules.
FooBarWidget authored
500 if (group.size >= options.min_processes) or
501 (!spawning_allowed(group, options)):
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
502 group.spawning = false
503 group.spawner_thread = null
504 return
505
506
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
507 private function detach_without_lock(identifier):
508 for group in groups:
509 processes = group.processes
510 for process_info in processes:
511 if process_info.identifier == identifier:
512 # Found a matching process.
513 process_info.detached = true
514 processes.remove(process_info.iterator)
515 group.size--
516 if processes.empty():
a4e53cb @FooBarWidget Make the ApplicationPool code DRYer by moving some code into functions
FooBarWidget authored
517 detach_group_without_lock(group)
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
518 if process_info.sessions == 0:
519 inactive_apps.remove(process_info.ia_iterator)
520 else:
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
521 mutate_active(active - 1)
522 mutate_count(count - 1)
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the conn…
FooBarWidget authored
523 return true
524 return false
525
526
712efad @FooBarWidget Update ApplicationPool algorithm description: move some code pieces a…
FooBarWidget authored
527 # The following function is to be called when a session has been closed.
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback…
FooBarWidget authored
528 # _process_info_ is a weak reference to the ProcessInfo that belongs to
529 # the process whose session has been closed; it evaluates to NULL if the
530 # ProcessInfo object that it belongs to has been destroyed.
b4ef02e @FooBarWidget Session close callback should accept a const Session pointer.
FooBarWidget authored
531 callback session_has_been_closed(session, process_info):
395b9d8 @FooBarWidget Minor updates.
FooBarWidget authored
532 Convert process_info into a normal reference.
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback…
FooBarWidget authored
533
534 # We check process_info.detached without locking. This should be safe:
535 # even if a boolean update isn't atomic on the current CPU, a non-zero
395b9d8 @FooBarWidget Minor updates.
FooBarWidget authored
536 # value evaluates to true. Once true, _detached_ will never become false,
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback…
FooBarWidget authored
537 # so instruction reorderings by the compiler or CPU won't cause any
538 # damage.
539 if (process_info == null) or (process_info.detached):
540 return
541
712efad @FooBarWidget Update ApplicationPool algorithm description: move some code pieces a…
FooBarWidget authored
542 lock.synchronize:
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback…
FooBarWidget authored
543 if process_info.detached:
544 return
545
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
546 group = groups[process_info.group_name]
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback…
FooBarWidget authored
547 processes = group.processes
548 process_info.processed++
549
550 if (group.max_requests > 0) and (process_info.processed >= group.max_requests):
551 # The application process has processed its maximum allowed
552 # number of requests, so we shut it down.
553 process_info.detached = true
554 processes.remove(process_info.iterator)
555 group.size--
556 if processes.empty():
a4e53cb @FooBarWidget Make the ApplicationPool code DRYer by moving some code into functions
FooBarWidget authored
557 detach_group_without_lock(group)
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
558 mutate_count(count - 1)
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback…
FooBarWidget authored
559 if (process_info.sessions == 0):
560 inactive_apps.remove(process_info.ia_iterator)
712efad @FooBarWidget Update ApplicationPool algorithm description: move some code pieces a…
FooBarWidget authored
561 else:
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
562 mutate_active(active - 1)
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback…
FooBarWidget authored
563 else:
564 process_info.last_used = current_time()
565 process_info.sessions--
566 if (process_info.sessions == 0):
567 processes.move_to_front(process_info.iterator)
12bce3f @FooBarWidget Minor changes
FooBarWidget authored
568 process_info.ia_iterator = inactive_apps.add_to_back(process_info)
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
569 mutate_active(active - 1)
712efad @FooBarWidget Update ApplicationPool algorithm description: move some code pieces a…
FooBarWidget authored
570
571
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
572 # The following thread will be responsible for cleaning up idle application
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
573 # process, i.e. processes that haven't been used for a while.
49e3fd3 @redmar added docs about setting the PassengerPoolIdleTime to 0.
redmar authored
574 # This can be disabled per app when setting it's maxIdleTime to 0.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
575 thread cleaner:
0e8110d @FooBarWidget Explicitly document locking in the ApplicationPool algorithm doucment…
FooBarWidget authored
576 lock.synchronize:
38a2816 @FooBarWidget Make the pool cleaner thread more efficient.
FooBarWidget authored
577 while true:
578 # If MAX_IDLE_TIME is 0 we don't clean up any processes,
579 # giving us the option to persist the processes
580 # forever unless it's killed in order to free up space
581 # for another process.
582 if (MAX_IDLE_TIME == 0):
583 Wait until the thread has been signalled to quit
584 or until MAX_IDLE_TIME changed.
585 if thread has been signalled to quit:
586 return
587 else:
588 restart loop
589 else:
590 Wait until MAX_IDLE_TIME seconds have passed,
591 or until the thread has been signalled to quit,
592 or until MAX_IDLE_TIME changed.
593 if thread has been signalled to quit:
594 return
595 else if MAX_IDLE_TIME changed:
596 restart loop
597
598 # Invariant:
599 # From this point on, MAX_IDLE_TIME > 0
bb8d4a8 @FooBarWidget Get rid of the global queue in StandardApplicationPool:
FooBarWidget authored
600
0e8110d @FooBarWidget Explicitly document locking in the ApplicationPool algorithm doucment…
FooBarWidget authored
601 now = current_time()
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
602 for all process_info in inactive_apps:
f569229 @FooBarWidget Fix some inconsistencies in the application pool algorithm description.
FooBarWidget authored
603 if (now - process_info.last_used > MAX_IDLE_TIME):
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
604 process = process_info.process
0fa0464 @FooBarWidget Group application pool processes by group name, not by app root.
FooBarWidget authored
605 group = groups[process_info.group_name]
f569229 @FooBarWidget Fix some inconsistencies in the application pool algorithm description.
FooBarWidget authored
606 if (group.size > group.min_processes):
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
607 processes = group.processes
608 processes.remove(process_info.iterator)
609 process_info.detached = true
610 inactive_apps.remove(process_info.ia_iterator)
611 group.size--
4193922 @FooBarWidget Implement asynchronous spawning of application processes.
FooBarWidget authored
612 mutate_count(count - 1)
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
613 if processes.empty():
a4e53cb @FooBarWidget Make the ApplicationPool code DRYer by moving some code into functions
FooBarWidget authored
614 detach_group_without_lock(group)
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing condi…
FooBarWidget authored
615
Something went wrong with that request. Please try again.