passenger 4.0.45 → 4.0.46
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/.editorconfig +19 -0
- data/CHANGELOG +47 -0
- data/CONTRIBUTING.md +9 -1
- data/CONTRIBUTORS +4 -0
- data/Vagrantfile +7 -3
- data/build/agents.rb +1 -0
- data/build/misc.rb +6 -4
- data/dev/vagrant/bashrc +2 -0
- data/doc/Design and Architecture.txt +9 -7
- data/doc/Users guide Apache.idmap.txt +2 -0
- data/doc/Users guide Apache.txt +24 -4
- data/doc/Users guide Nginx.idmap.txt +4 -0
- data/doc/Users guide Nginx.txt +23 -4
- data/doc/images/code_walkthrough.jpg +0 -0
- data/doc/users_guide_snippets/installation.txt +38 -0
- data/ext/common/AgentsStarter.h +6 -1
- data/ext/common/ApplicationPool2/Common.h +17 -2
- data/ext/common/ApplicationPool2/DirectSpawner.h +5 -11
- data/ext/common/ApplicationPool2/DummySpawner.h +2 -4
- data/ext/common/ApplicationPool2/ErrorRenderer.h +119 -0
- data/ext/common/ApplicationPool2/Implementation.cpp +159 -11
- data/ext/common/ApplicationPool2/Options.h +16 -7
- data/ext/common/ApplicationPool2/Pool.h +28 -24
- data/ext/common/ApplicationPool2/Process.h +1 -9
- data/ext/common/ApplicationPool2/SmartSpawner.h +15 -18
- data/ext/common/ApplicationPool2/Spawner.h +18 -14
- data/ext/common/ApplicationPool2/SpawnerFactory.h +12 -30
- data/ext/common/Constants.h +1 -1
- data/ext/common/Exceptions.h +15 -2
- data/ext/common/UnionStation/Core.h +9 -0
- data/ext/common/Utils/JsonUtils.h +53 -0
- data/ext/common/Utils/ProcessMetricsCollector.h +1 -1
- data/ext/common/Utils/SpeedMeter.h +7 -3
- data/ext/common/Utils/SystemMetricsCollector.h +8 -6
- data/ext/common/agents/HelperAgent/Main.cpp +4 -4
- data/ext/common/agents/HelperAgent/RequestHandler.h +115 -56
- data/ext/nginx/ConfigurationCommands.c +1 -1
- data/ext/nginx/ConfigurationCommands.c.erb +6 -1
- data/ext/nginx/ContentHandler.c +2 -1
- data/ext/nginx/config +1 -1
- data/helper-scripts/node-loader.js +23 -0
- data/helper-scripts/wsgi-loader.py +12 -4
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/active_support3_extensions/init.rb +39 -78
- data/lib/phusion_passenger/constants.rb +3 -1
- data/lib/phusion_passenger/loader_shared_helpers.rb +10 -5
- data/lib/phusion_passenger/nginx/config_options.rb +3 -1
- data/lib/phusion_passenger/packaging.rb +1 -0
- data/lib/phusion_passenger/public_api.rb +108 -16
- data/lib/phusion_passenger/rack/thread_handler_extension.rb +1 -0
- data/lib/phusion_passenger/request_handler.rb +2 -2
- data/lib/phusion_passenger/request_handler/thread_handler.rb +28 -46
- data/lib/phusion_passenger/standalone/command.rb +8 -1
- data/lib/phusion_passenger/standalone/main.rb +0 -1
- data/lib/phusion_passenger/standalone/start_command.rb +4 -0
- data/lib/phusion_passenger/union_station/connection.rb +67 -0
- data/lib/phusion_passenger/{analytics_logger.rb → union_station/core.rb} +55 -256
- data/lib/phusion_passenger/union_station/transaction.rb +168 -0
- data/lib/phusion_passenger/utils.rb +4 -0
- data/lib/phusion_passenger/utils/lock.rb +62 -0
- data/resources/mime.types +1 -0
- data/resources/templates/error_layout.html.template +2 -0
- data/resources/templates/standalone/config.erb +1 -0
- data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +5 -3
- data/test/cxx/ApplicationPool2/PoolTest.cpp +13 -3
- data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +16 -13
- data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +6 -0
- data/test/cxx/FileBackedPipeTest.cpp +1 -1
- data/test/cxx/RequestHandlerTest.cpp +158 -2
- data/test/cxx/ServerInstanceDirTest.cpp +2 -0
- data/test/cxx/TestSupport.h +21 -2
- data/test/cxx/UtilsTest.cpp +1 -0
- data/test/ruby/classic_rails/loader_spec.rb +0 -1
- data/test/ruby/classic_rails/preloader_spec.rb +0 -1
- data/test/ruby/rails3.0/loader_spec.rb +2 -2
- data/test/ruby/rails3.0/preloader_spec.rb +2 -2
- data/test/ruby/rails3.1/loader_spec.rb +2 -2
- data/test/ruby/rails3.1/preloader_spec.rb +2 -2
- data/test/ruby/rails3.2/loader_spec.rb +2 -2
- data/test/ruby/rails3.2/preloader_spec.rb +2 -2
- data/test/ruby/rails4.0/loader_spec.rb +2 -2
- data/test/ruby/rails4.0/preloader_spec.rb +2 -2
- data/test/ruby/request_handler_spec.rb +8 -8
- data/test/ruby/shared/rails/{analytics_logging_extensions_sharedspec.rb → union_station_extensions_sharedspec.rb} +5 -4
- data/test/ruby/union_station_spec.rb +283 -0
- data/test/stub/wsgi/passenger_wsgi.py +41 -5
- metadata +12 -7
- metadata.gz.asc +7 -7
- data/helper-scripts/wsgi-preloader.py +0 -1
- data/lib/phusion_passenger/standalone/package_runtime_command.rb +0 -105
- data/test/ruby/analytics_logger_spec.rb +0 -283
Binary file
|
@@ -141,6 +141,9 @@ sudo apt-get install nginx-extras passenger
|
|
141
141
|
--------------------------------------------------------------
|
142
142
|
+
|
143
143
|
3. Edit `/etc/nginx/nginx.conf` and uncomment `passenger_root` and `passenger_ruby`.
|
144
|
+
+
|
145
|
+
Especially <<PassengerRoot,passenger_root>> is important: Phusion Passenger won't work without it! If you don't see a commented version of `passenger_root` inside nginx.conf, then you need to <<inserting_passenger_root_for_apt,insert it yourself>>.
|
146
|
+
+
|
144
147
|
4. Restart Nginx:
|
145
148
|
+
|
146
149
|
--------------------------------------------------------------
|
@@ -180,6 +183,9 @@ ifdef::nginx[]
|
|
180
183
|
sudo apt-get install nginx-extras passenger-enterprise
|
181
184
|
--------------------------------------------------------------
|
182
185
|
4. Edit `/etc/nginx/nginx.conf` and uncomment `passenger_root` and `passenger_ruby`.
|
186
|
+
+
|
187
|
+
Especially <<PassengerRoot,passenger_root>> is important: Phusion Passenger won't work without it! If you don't see a commented version of `passenger_root` inside nginx.conf, then you need to <<inserting_passenger_root_for_apt,insert it yourself>>.
|
188
|
+
+
|
183
189
|
5. Restart Nginx:
|
184
190
|
+
|
185
191
|
--------------------------------------------------------------
|
@@ -204,6 +210,38 @@ sudo apt-get install passenger-enterprise
|
|
204
210
|
--------------------------------------------------------------
|
205
211
|
endif::[]
|
206
212
|
|
213
|
+
ifdef::nginx[]
|
214
|
+
[[inserting_passenger_root_for_apt]]
|
215
|
+
==== Inserting `passenger_root` into nginx.conf
|
216
|
+
|
217
|
+
During step 3 of the 'Installing packages' subsection, you were instructed to uncomment the <<PassengerRoot,passenger_root>> directive in `/etc/nginx/nginx.conf`. If there is no commented version in there, then you need to insert it yourself.
|
218
|
+
|
219
|
+
First, run the following command and take note of its output:
|
220
|
+
|
221
|
+
-----------------------------------
|
222
|
+
/usr/bin/passenger-config --root
|
223
|
+
-----------------------------------
|
224
|
+
|
225
|
+
Next, insert the following snippet into `/etc/nginx/nginx.conf`, under the `http` block:
|
226
|
+
|
227
|
+
-------------------------------------------------------------
|
228
|
+
passenger_root whatever_value_you_got_from_previous_command;
|
229
|
+
-------------------------------------------------------------
|
230
|
+
|
231
|
+
Here is an example:
|
232
|
+
|
233
|
+
-------------------------------------------------------------
|
234
|
+
...
|
235
|
+
http {
|
236
|
+
# path-to-locations.ini is given to you by `passenger-config --root`.
|
237
|
+
passenger_root /path-to-locations.ini;
|
238
|
+
...
|
239
|
+
}
|
240
|
+
-------------------------------------------------------------
|
241
|
+
|
242
|
+
Once you're done editing nginx.conf, continue with step 4.
|
243
|
+
endif::nginx[]
|
244
|
+
|
207
245
|
|
208
246
|
=== Installing or upgrading on Red Hat, Fedora, CentOS or ScientificLinux
|
209
247
|
|
data/ext/common/AgentsStarter.h
CHANGED
@@ -535,10 +535,13 @@ public:
|
|
535
535
|
guard.clear();
|
536
536
|
if (e == ENOENT) {
|
537
537
|
string passengerRootConfig;
|
538
|
+
string docURL;
|
538
539
|
if (type == AS_APACHE) {
|
539
540
|
passengerRootConfig = "PassengerRoot";
|
541
|
+
docURL = APACHE2_DOC_URL "#PassengerRoot";
|
540
542
|
} else {
|
541
543
|
passengerRootConfig = "passenger_root";
|
544
|
+
docURL = NGINX_DOC_URL "#PassengerRoot";
|
542
545
|
}
|
543
546
|
throw RuntimeException("Unable to start the Phusion Passenger watchdog "
|
544
547
|
"because its executable (" + watchdogFilename + ") does "
|
@@ -546,7 +549,9 @@ public:
|
|
546
549
|
"installation is broken or incomplete, or that your '" +
|
547
550
|
passengerRootConfig + "' directive is set to the wrong value. "
|
548
551
|
"Please reinstall Phusion Passenger or fix your '" +
|
549
|
-
passengerRootConfig + "' directive, whichever is applicable."
|
552
|
+
passengerRootConfig + "' directive, whichever is applicable. "
|
553
|
+
"To learn how to fix '" + passengerRootConfig + "', please read " +
|
554
|
+
docURL);
|
550
555
|
} else {
|
551
556
|
throw SystemException("Unable to start the Phusion Passenger watchdog (" +
|
552
557
|
watchdogFilename + ")", e);
|
@@ -29,7 +29,10 @@
|
|
29
29
|
#include <boost/shared_ptr.hpp>
|
30
30
|
#include <boost/function.hpp>
|
31
31
|
#include <oxt/tracable_exception.hpp>
|
32
|
+
#include <ResourceLocator.h>
|
32
33
|
#include <RandomGenerator.h>
|
34
|
+
#include <UnionStation/Core.h>
|
35
|
+
#include <UnionStation/Transaction.h>
|
33
36
|
#include <ApplicationPool2/Options.h>
|
34
37
|
#include <Utils/StringMap.h>
|
35
38
|
|
@@ -183,6 +186,12 @@ struct Ticket {
|
|
183
186
|
};
|
184
187
|
|
185
188
|
struct SpawnerConfig {
|
189
|
+
// Used by error pages.
|
190
|
+
ResourceLocator resourceLocator;
|
191
|
+
|
192
|
+
// Used for Union Station logging.
|
193
|
+
UnionStation::CorePtr unionStationCore;
|
194
|
+
|
186
195
|
// Used by SmartSpawner and DirectSpawner.
|
187
196
|
/** A random generator to use. */
|
188
197
|
RandomGeneratorPtr randomGenerator;
|
@@ -192,8 +201,12 @@ struct SpawnerConfig {
|
|
192
201
|
unsigned int spawnerCreationSleepTime;
|
193
202
|
unsigned int spawnTime;
|
194
203
|
|
195
|
-
SpawnerConfig(const
|
196
|
-
|
204
|
+
SpawnerConfig(const ResourceLocator &_resourceLocator,
|
205
|
+
const UnionStation::CorePtr &_unionStationCore = UnionStation::CorePtr(),
|
206
|
+
const RandomGeneratorPtr &randomGenerator = RandomGeneratorPtr())
|
207
|
+
: resourceLocator(_resourceLocator),
|
208
|
+
unionStationCore(_unionStationCore),
|
209
|
+
concurrency(1),
|
197
210
|
spawnerCreationSleepTime(0),
|
198
211
|
spawnTime(0)
|
199
212
|
{
|
@@ -209,6 +222,8 @@ typedef boost::shared_ptr<SpawnerConfig> SpawnerConfigPtr;
|
|
209
222
|
|
210
223
|
ExceptionPtr copyException(const tracable_exception &e);
|
211
224
|
void rethrowException(const ExceptionPtr &e);
|
225
|
+
void processAndLogNewSpawnException(SpawnException &e, const Options &options,
|
226
|
+
const SpawnerConfigPtr &config);
|
212
227
|
|
213
228
|
} // namespace ApplicationPool2
|
214
229
|
} // namespace Passenger
|
@@ -111,10 +111,10 @@ private:
|
|
111
111
|
shared_array<const char *> &args) const
|
112
112
|
{
|
113
113
|
vector<string> startCommandArgs;
|
114
|
-
string agentsDir = resourceLocator.getAgentsDir();
|
114
|
+
string agentsDir = config->resourceLocator.getAgentsDir();
|
115
115
|
vector<string> command;
|
116
116
|
|
117
|
-
split(options.getStartCommand(resourceLocator), '\t', startCommandArgs);
|
117
|
+
split(options.getStartCommand(config->resourceLocator), '\t', startCommandArgs);
|
118
118
|
if (startCommandArgs.empty()) {
|
119
119
|
throw RuntimeException("No startCommand given");
|
120
120
|
}
|
@@ -144,17 +144,11 @@ private:
|
|
144
144
|
}
|
145
145
|
|
146
146
|
public:
|
147
|
-
DirectSpawner(const
|
148
|
-
const
|
149
|
-
|
150
|
-
: Spawner(_resourceLocator)
|
147
|
+
DirectSpawner(const ServerInstanceDir::GenerationPtr &_generation,
|
148
|
+
const SpawnerConfigPtr &_config)
|
149
|
+
: Spawner(_config)
|
151
150
|
{
|
152
151
|
generation = _generation;
|
153
|
-
if (_config == NULL) {
|
154
|
-
config = boost::make_shared<SpawnerConfig>();
|
155
|
-
} else {
|
156
|
-
config = _config;
|
157
|
-
}
|
158
152
|
}
|
159
153
|
|
160
154
|
virtual ProcessPtr spawn(const Options &options) {
|
@@ -37,16 +37,14 @@ using namespace oxt;
|
|
37
37
|
|
38
38
|
class DummySpawner: public Spawner {
|
39
39
|
private:
|
40
|
-
SpawnerConfigPtr config;
|
41
40
|
boost::mutex lock;
|
42
41
|
unsigned int count;
|
43
42
|
|
44
43
|
public:
|
45
44
|
unsigned int cleanCount;
|
46
45
|
|
47
|
-
DummySpawner(const
|
48
|
-
: Spawner(
|
49
|
-
config(_config)
|
46
|
+
DummySpawner(const SpawnerConfigPtr &_config)
|
47
|
+
: Spawner(_config)
|
50
48
|
{
|
51
49
|
count = 0;
|
52
50
|
cleanCount = 0;
|
@@ -0,0 +1,119 @@
|
|
1
|
+
/*
|
2
|
+
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
+
* Copyright (c) 2014 Phusion
|
4
|
+
*
|
5
|
+
* "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
6
|
+
*
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
12
|
+
* furnished to do so, subject to the following conditions:
|
13
|
+
*
|
14
|
+
* The above copyright notice and this permission notice shall be included in
|
15
|
+
* all copies or substantial portions of the Software.
|
16
|
+
*
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23
|
+
* THE SOFTWARE.
|
24
|
+
*/
|
25
|
+
#ifndef _PASSENGER_APPLICATION_POOL2_ERROR_RENDERER_H_
|
26
|
+
#define _PASSENGER_APPLICATION_POOL2_ERROR_RENDERER_H_
|
27
|
+
|
28
|
+
#include <string>
|
29
|
+
#include <map>
|
30
|
+
#include <cctype>
|
31
|
+
|
32
|
+
#include <ApplicationPool2/Options.h>
|
33
|
+
#include <Constants.h>
|
34
|
+
#include <ResourceLocator.h>
|
35
|
+
#include <StaticString.h>
|
36
|
+
#include <Exceptions.h>
|
37
|
+
#include <Utils/StringMap.h>
|
38
|
+
#include <Utils/Template.h>
|
39
|
+
#include <Utils/IOUtils.h>
|
40
|
+
|
41
|
+
namespace Passenger {
|
42
|
+
namespace ApplicationPool2 {
|
43
|
+
|
44
|
+
using namespace std;
|
45
|
+
using namespace boost;
|
46
|
+
using namespace oxt;
|
47
|
+
|
48
|
+
|
49
|
+
class ErrorRenderer {
|
50
|
+
private:
|
51
|
+
string templatesDir, cssFile, errorLayoutFile;
|
52
|
+
|
53
|
+
public:
|
54
|
+
ErrorRenderer(const ResourceLocator &resourceLocator) {
|
55
|
+
templatesDir = resourceLocator.getResourcesDir() + "/templates";
|
56
|
+
cssFile = templatesDir + "/error_layout.css";
|
57
|
+
errorLayoutFile = templatesDir + "/error_layout.html.template";
|
58
|
+
}
|
59
|
+
|
60
|
+
string renderWithDetails(const StaticString &message,
|
61
|
+
const Options &options,
|
62
|
+
const SpawnException *e = NULL) const
|
63
|
+
{
|
64
|
+
string generalErrorFile =
|
65
|
+
(e != NULL && e->isHTML())
|
66
|
+
? templatesDir + "/general_error_with_html.html.template"
|
67
|
+
: templatesDir + "/general_error.html.template";
|
68
|
+
string css = readAll(cssFile);
|
69
|
+
StringMap<StaticString> params;
|
70
|
+
|
71
|
+
params.set("CSS", css);
|
72
|
+
params.set("APP_ROOT", options.appRoot);
|
73
|
+
params.set("RUBY", options.ruby);
|
74
|
+
params.set("ENVIRONMENT", options.environment);
|
75
|
+
params.set("MESSAGE", message);
|
76
|
+
params.set("IS_RUBY_APP",
|
77
|
+
(options.appType == "classic-rails" || options.appType == "rack")
|
78
|
+
? "true" : "false");
|
79
|
+
if (e != NULL) {
|
80
|
+
params.set("TITLE", "Web application could not be started");
|
81
|
+
// Store all SpawnException annotations into 'params',
|
82
|
+
// but convert its name to uppercase.
|
83
|
+
const map<string, string> &annotations = e->getAnnotations();
|
84
|
+
map<string, string>::const_iterator it, end = annotations.end();
|
85
|
+
for (it = annotations.begin(); it != end; it++) {
|
86
|
+
string name = it->first;
|
87
|
+
for (string::size_type i = 0; i < name.size(); i++) {
|
88
|
+
name[i] = toupper(name[i]);
|
89
|
+
}
|
90
|
+
params.set(name, it->second);
|
91
|
+
}
|
92
|
+
} else {
|
93
|
+
params.set("TITLE", "Internal server error");
|
94
|
+
}
|
95
|
+
|
96
|
+
string content = Template::apply(readAll(generalErrorFile), params);
|
97
|
+
params.set("CONTENT", content);
|
98
|
+
|
99
|
+
return Template::apply(readAll(errorLayoutFile), params);
|
100
|
+
}
|
101
|
+
|
102
|
+
string renderWithoutDetails() const {
|
103
|
+
string templateFile = templatesDir + "/undisclosed_error.html.template";
|
104
|
+
StringMap<StaticString> params;
|
105
|
+
|
106
|
+
params.set("PROGRAM_NAME", PROGRAM_NAME);
|
107
|
+
params.set("NGINX_DOC_URL", NGINX_DOC_URL);
|
108
|
+
params.set("APACHE2_DOC_URL", APACHE2_DOC_URL);
|
109
|
+
params.set("STANDALONE_DOC_URL", STANDALONE_DOC_URL);
|
110
|
+
|
111
|
+
return Template::apply(readAll(templateFile), params);
|
112
|
+
}
|
113
|
+
};
|
114
|
+
|
115
|
+
|
116
|
+
} // namespace ApplicationPool2
|
117
|
+
} // namespace Passenger
|
118
|
+
|
119
|
+
#endif /* _PASSENGER_APPLICATION_POOL2_ERROR_RENDERER_H_ */
|
@@ -25,6 +25,8 @@
|
|
25
25
|
#include <typeinfo>
|
26
26
|
#include <algorithm>
|
27
27
|
#include <utility>
|
28
|
+
#include <sstream>
|
29
|
+
#include <limits.h>
|
28
30
|
#include <boost/make_shared.hpp>
|
29
31
|
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
30
32
|
#include <oxt/backtrace.hpp>
|
@@ -32,10 +34,13 @@
|
|
32
34
|
#include <ApplicationPool2/SuperGroup.h>
|
33
35
|
#include <ApplicationPool2/Group.h>
|
34
36
|
#include <ApplicationPool2/PipeWatcher.h>
|
37
|
+
#include <ApplicationPool2/ErrorRenderer.h>
|
35
38
|
#include <Exceptions.h>
|
36
39
|
#include <MessageReadersWriters.h>
|
40
|
+
#include <Utils.h>
|
37
41
|
#include <Utils/ScopeGuard.h>
|
38
42
|
#include <Utils/MessageIO.h>
|
43
|
+
#include <Utils/JsonUtils.h>
|
39
44
|
|
40
45
|
namespace Passenger {
|
41
46
|
namespace ApplicationPool2 {
|
@@ -136,6 +141,146 @@ rethrowException(const ExceptionPtr &e) {
|
|
136
141
|
throw tracable_exception(*e);
|
137
142
|
}
|
138
143
|
|
144
|
+
void processAndLogNewSpawnException(SpawnException &e, const Options &options,
|
145
|
+
const SpawnerConfigPtr &config)
|
146
|
+
{
|
147
|
+
TRACE_POINT();
|
148
|
+
UnionStation::TransactionPtr transaction;
|
149
|
+
ErrorRenderer renderer(config->resourceLocator);
|
150
|
+
string appMessage = e.getErrorPage();
|
151
|
+
string errorId;
|
152
|
+
char filename[PATH_MAX];
|
153
|
+
stringstream stream;
|
154
|
+
|
155
|
+
if (options.analytics && config->unionStationCore != NULL) {
|
156
|
+
try {
|
157
|
+
UPDATE_TRACE_POINT();
|
158
|
+
transaction = config->unionStationCore->newTransaction(
|
159
|
+
options.getAppGroupName(),
|
160
|
+
"exceptions",
|
161
|
+
options.unionStationKey);
|
162
|
+
errorId = transaction->getTxnId();
|
163
|
+
} catch (const tracable_exception &e2) {
|
164
|
+
transaction.reset();
|
165
|
+
P_WARN("Cannot log to Union Station: " << e2.what() <<
|
166
|
+
"\n Backtrace:\n" << e2.backtrace());
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
UPDATE_TRACE_POINT();
|
171
|
+
if (appMessage.empty()) {
|
172
|
+
appMessage = "none";
|
173
|
+
}
|
174
|
+
if (errorId.empty()) {
|
175
|
+
errorId = config->randomGenerator->generateHexString(4);
|
176
|
+
}
|
177
|
+
e.set("error_id", errorId);
|
178
|
+
|
179
|
+
try {
|
180
|
+
int fd = -1;
|
181
|
+
FdGuard guard(fd, true);
|
182
|
+
string errorPage;
|
183
|
+
|
184
|
+
UPDATE_TRACE_POINT();
|
185
|
+
errorPage = renderer.renderWithDetails(appMessage, options, &e);
|
186
|
+
|
187
|
+
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
188
|
+
snprintf(filename, PATH_MAX, "%s/passenger-error-XXXXXX.html",
|
189
|
+
getSystemTempDir());
|
190
|
+
fd = mkstemps(filename, sizeof(".html") - 1);
|
191
|
+
#else
|
192
|
+
snprintf(filename, PATH_MAX, "%s/passenger-error.XXXXXX",
|
193
|
+
getSystemTempDir());
|
194
|
+
fd = mkstemp(filename);
|
195
|
+
#endif
|
196
|
+
if (fd == -1) {
|
197
|
+
int e = errno;
|
198
|
+
throw SystemException("Cannot generate a temporary filename",
|
199
|
+
e);
|
200
|
+
}
|
201
|
+
|
202
|
+
UPDATE_TRACE_POINT();
|
203
|
+
writeExact(fd, errorPage);
|
204
|
+
} catch (const SystemException &e2) {
|
205
|
+
filename[0] = '\0';
|
206
|
+
P_ERROR("Cannot render an error page: " << e2.what() << "\n" <<
|
207
|
+
e2.backtrace());
|
208
|
+
}
|
209
|
+
|
210
|
+
if (transaction != NULL) {
|
211
|
+
try {
|
212
|
+
UPDATE_TRACE_POINT();
|
213
|
+
transaction->message("Context: spawning");
|
214
|
+
transaction->message("Message: " +
|
215
|
+
jsonString(e.what()));
|
216
|
+
transaction->message("App message: " +
|
217
|
+
jsonString(appMessage));
|
218
|
+
|
219
|
+
const char *kind;
|
220
|
+
switch (e.getErrorKind()) {
|
221
|
+
case SpawnException::PRELOADER_STARTUP_ERROR:
|
222
|
+
kind = "PRELOADER_STARTUP_ERROR";
|
223
|
+
break;
|
224
|
+
case SpawnException::PRELOADER_STARTUP_PROTOCOL_ERROR:
|
225
|
+
kind = "PRELOADER_STARTUP_PROTOCOL_ERROR";
|
226
|
+
break;
|
227
|
+
case SpawnException::PRELOADER_STARTUP_TIMEOUT:
|
228
|
+
kind = "PRELOADER_STARTUP_TIMEOUT";
|
229
|
+
break;
|
230
|
+
case SpawnException::PRELOADER_STARTUP_EXPLAINABLE_ERROR:
|
231
|
+
kind = "PRELOADER_STARTUP_EXPLAINABLE_ERROR";
|
232
|
+
break;
|
233
|
+
case SpawnException::APP_STARTUP_ERROR:
|
234
|
+
kind = "APP_STARTUP_ERROR";
|
235
|
+
break;
|
236
|
+
case SpawnException::APP_STARTUP_PROTOCOL_ERROR:
|
237
|
+
kind = "APP_STARTUP_PROTOCOL_ERROR";
|
238
|
+
break;
|
239
|
+
case SpawnException::APP_STARTUP_TIMEOUT:
|
240
|
+
kind = "APP_STARTUP_TIMEOUT";
|
241
|
+
break;
|
242
|
+
case SpawnException::APP_STARTUP_EXPLAINABLE_ERROR:
|
243
|
+
kind = "APP_STARTUP_EXPLAINABLE_ERROR";
|
244
|
+
break;
|
245
|
+
default:
|
246
|
+
kind = "UNDEFINED_ERROR";
|
247
|
+
break;
|
248
|
+
}
|
249
|
+
transaction->message(string("Kind: ") + kind);
|
250
|
+
|
251
|
+
Json::Value details;
|
252
|
+
const map<string, string> &annotations = e.getAnnotations();
|
253
|
+
map<string, string>::const_iterator it, end = annotations.end();
|
254
|
+
|
255
|
+
for (it = annotations.begin(); it != end; it++) {
|
256
|
+
details[it->first] = it->second;
|
257
|
+
}
|
258
|
+
|
259
|
+
// This information is not very useful. Union Station
|
260
|
+
// already collects system metrics.
|
261
|
+
details.removeMember("system_metrics");
|
262
|
+
// Don't include environment variables because they may
|
263
|
+
// contain sensitive information.
|
264
|
+
details.removeMember("envvars");
|
265
|
+
|
266
|
+
transaction->message("Details: " + stringifyJson(details));
|
267
|
+
} catch (const tracable_exception &e2) {
|
268
|
+
P_WARN("Cannot log to Union Station: " << e2.what() <<
|
269
|
+
"\n Backtrace:\n" << e2.backtrace());
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
UPDATE_TRACE_POINT();
|
274
|
+
stream << "Could not spawn process for application " << options.appRoot <<
|
275
|
+
": " << e.what() << "\n" <<
|
276
|
+
" Error ID: " << errorId << "\n";
|
277
|
+
if (filename[0] != '\0') {
|
278
|
+
stream << " Error details saved to: " << filename << "\n";
|
279
|
+
}
|
280
|
+
stream << " Message from application: " << appMessage << "\n";
|
281
|
+
P_ERROR(stream.str());
|
282
|
+
}
|
283
|
+
|
139
284
|
|
140
285
|
const SuperGroupPtr
|
141
286
|
Pool::getSuperGroup(const char *name) {
|
@@ -155,7 +300,7 @@ SuperGroup::runAllActions(const vector<Callback> &actions) {
|
|
155
300
|
|
156
301
|
string
|
157
302
|
SuperGroup::generateSecret() const {
|
158
|
-
return getPool()->
|
303
|
+
return getPool()->getRandomGenerator()->generateAsciiString(43);
|
159
304
|
}
|
160
305
|
|
161
306
|
void
|
@@ -187,6 +332,8 @@ SuperGroup::realDoInitialize(const Options &options, unsigned int generation) {
|
|
187
332
|
vector<ComponentInfo> componentInfos;
|
188
333
|
vector<ComponentInfo>::const_iterator it;
|
189
334
|
ExceptionPtr exception;
|
335
|
+
|
336
|
+
PoolPtr pool = getPool();
|
190
337
|
|
191
338
|
P_TRACE(2, "Initializing SuperGroup " << inspect() << " in the background...");
|
192
339
|
try {
|
@@ -198,13 +345,15 @@ SuperGroup::realDoInitialize(const Options &options, unsigned int generation) {
|
|
198
345
|
string message = "The directory " +
|
199
346
|
options.appRoot +
|
200
347
|
" does not seem to contain a web application.";
|
201
|
-
|
202
|
-
|
348
|
+
boost::shared_ptr<SpawnException> spawnException =
|
349
|
+
boost::make_shared<SpawnException>(
|
350
|
+
message, message, false);
|
351
|
+
exception = spawnException;
|
352
|
+
processAndLogNewSpawnException(*spawnException, options,
|
353
|
+
pool->getSpawnerConfig());
|
203
354
|
}
|
204
355
|
|
205
|
-
PoolPtr pool = getPool();
|
206
356
|
Pool::DebugSupportPtr debug = pool->debugSupport;
|
207
|
-
|
208
357
|
vector<Callback> actions;
|
209
358
|
{
|
210
359
|
if (debug != NULL && debug->superGroup) {
|
@@ -805,7 +954,9 @@ Group::spawnThreadRealMain(const SpawnerPtr &spawner, const Options &options, un
|
|
805
954
|
this_thread::restore_interruption ri(di);
|
806
955
|
this_thread::restore_syscall_interruption rsi(dsi);
|
807
956
|
if (shouldFail) {
|
808
|
-
|
957
|
+
SpawnException e("Simulated failure");
|
958
|
+
processAndLogNewSpawnException(e, options, pool->getSpawnerConfig());
|
959
|
+
throw e;
|
809
960
|
} else {
|
810
961
|
process = spawner->spawn(options);
|
811
962
|
process->setGroup(shared_from_this());
|
@@ -878,9 +1029,6 @@ Group::spawnThreadRealMain(const SpawnerPtr &spawner, const Options &options, un
|
|
878
1029
|
} else {
|
879
1030
|
// TODO: sure this is the best thing? if there are
|
880
1031
|
// processes currently alive we should just use them.
|
881
|
-
P_ERROR("Could not spawn process for group " << name <<
|
882
|
-
": " << exception->what() << "\n" <<
|
883
|
-
exception->backtrace());
|
884
1032
|
if (enabledCount == 0) {
|
885
1033
|
enableAllDisablingProcesses(actions);
|
886
1034
|
}
|
@@ -1197,7 +1345,7 @@ Group::testOverflowRequestQueue() const {
|
|
1197
1345
|
|
1198
1346
|
const ResourceLocator &
|
1199
1347
|
Group::getResourceLocator() const {
|
1200
|
-
return getPool()->
|
1348
|
+
return getPool()->getSpawnerConfig()->resourceLocator;
|
1201
1349
|
}
|
1202
1350
|
|
1203
1351
|
// 'process' is not a reference so that bind(runAttachHooks, ...) causes the shared
|
@@ -1222,7 +1370,7 @@ Group::setupAttachOrDetachHook(const ProcessPtr process, HookScriptOptions &opti
|
|
1222
1370
|
|
1223
1371
|
string
|
1224
1372
|
Group::generateSecret(const SuperGroupPtr &superGroup) {
|
1225
|
-
return superGroup->getPool()->
|
1373
|
+
return superGroup->getPool()->getRandomGenerator()->generateAsciiString(43);
|
1226
1374
|
}
|
1227
1375
|
|
1228
1376
|
|