passenger 4.0.5 → 4.0.6
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.
- data.tar.gz.asc +7 -7
- data/.travis.yml +1 -2
- data/CONTRIBUTING.md +20 -5
- data/CONTRIBUTORS +67 -0
- data/LICENSE +1 -1
- data/NEWS +48 -0
- data/Rakefile +2 -2
- data/bin/passenger-config +18 -0
- data/bin/passenger-install-apache2-module +2 -0
- data/bin/passenger-install-nginx-module +11 -12
- data/bin/passenger-memory-stats +2 -0
- data/bin/passenger-status +152 -69
- data/build/agents.rb +1 -5
- data/build/basics.rb +26 -13
- data/build/cplusplus_support.rb +9 -0
- data/build/debian.rb +129 -0
- data/build/documentation.rb +6 -2
- data/build/integration_tests.rb +13 -2
- data/build/misc.rb +16 -0
- data/build/packaging.rb +67 -51
- data/build/preprocessor.rb +314 -0
- data/build/test_basics.rb +1 -0
- data/{debian → debian.template}/README.Debian +0 -0
- data/{debian → debian.template}/changelog +131 -0
- data/debian.template/compat +1 -0
- data/debian.template/control +71 -0
- data/debian.template/copyright +385 -0
- data/debian.template/libapache2-mod-passenger.install +3 -0
- data/{debian → debian.template}/libapache2-mod-passenger.postinst +0 -0
- data/{debian → debian.template}/libapache2-mod-passenger.prerm +0 -0
- data/debian.template/locations.ini +12 -0
- data/debian.template/passenger.conf +4 -0
- data/{debian → debian.template}/passenger.load +0 -0
- data/debian.template/patches/series +0 -0
- data/debian.template/repack.sh +42 -0
- data/debian.template/ruby-passenger-dev.install +3 -0
- data/debian.template/ruby-passenger-doc.install +2 -0
- data/debian.template/ruby-passenger.docs +4 -0
- data/debian.template/ruby-passenger.install +11 -0
- data/debian.template/ruby-passenger.manpages +4 -0
- data/debian.template/rules.template +35 -0
- data/debian.template/source/format +1 -0
- data/debian.template/watch +3 -0
- data/dev/run_travis.sh +46 -46
- data/doc/Architectural overview.html +2 -2
- data/doc/Packaging.html +27 -18
- data/doc/Packaging.txt.md +27 -18
- data/doc/Security of user switching support.html +2 -2
- data/doc/Users guide Apache.html +881 -95
- data/doc/Users guide Apache.idmap.txt +48 -6
- data/doc/Users guide Apache.txt +13 -1
- data/doc/Users guide Nginx.html +1063 -190
- data/doc/Users guide Nginx.idmap.txt +89 -45
- data/doc/Users guide Nginx.txt +45 -0
- data/doc/Users guide Standalone.html +7 -7
- data/doc/users_guide_snippets/alternative_for_flying_passenger.txt +1 -0
- data/doc/users_guide_snippets/environment_variables.txt +221 -0
- data/doc/users_guide_snippets/installation.txt +66 -17
- data/doc/users_guide_snippets/support_information.txt +3 -3
- data/doc/users_guide_snippets/tips.txt +352 -40
- data/ext/common/Account.h +4 -3
- data/ext/common/AccountsDatabase.h +6 -6
- data/ext/common/AgentsStarter.h +1 -13
- data/ext/common/ApplicationPool2/DirectSpawner.h +4 -4
- data/ext/common/ApplicationPool2/DummySpawner.h +1 -1
- data/ext/common/ApplicationPool2/Group.h +9 -4
- data/ext/common/ApplicationPool2/Implementation.cpp +6 -1
- data/ext/common/ApplicationPool2/Options.h +65 -37
- data/ext/common/ApplicationPool2/Pool.h +91 -41
- data/ext/common/ApplicationPool2/Process.h +6 -6
- data/ext/common/ApplicationPool2/SmartSpawner.h +14 -14
- data/ext/common/ApplicationPool2/Socket.h +1 -1
- data/ext/common/ApplicationPool2/Spawner.h +24 -16
- data/ext/common/ApplicationPool2/SpawnerFactory.h +9 -1
- data/ext/common/ApplicationPool2/SuperGroup.h +1 -1
- data/ext/common/Constants.h +1 -1
- data/ext/common/Logging.cpp +12 -7
- data/ext/common/MessageServer.h +7 -12
- data/ext/common/MultiLibeio.cpp +5 -5
- data/ext/common/ResourceLocator.h +2 -6
- data/ext/common/ServerInstanceDir.h +37 -10
- data/ext/common/UnionStation.h +10 -10
- data/ext/common/Utils.cpp +30 -4
- data/ext/common/Utils.h +7 -0
- data/ext/common/Utils/BlockingQueue.h +2 -2
- data/ext/common/Utils/Lock.h +2 -2
- data/ext/common/Utils/MessagePassing.h +2 -2
- data/ext/common/Utils/Timer.h +4 -4
- data/ext/common/agents/HelperAgent/AgentOptions.h +2 -0
- data/ext/common/agents/HelperAgent/Main.cpp +57 -16
- data/ext/common/agents/HelperAgent/RequestHandler.h +4 -1
- data/ext/common/agents/LoggingAgent/AdminController.h +91 -0
- data/ext/common/agents/LoggingAgent/LoggingServer.h +46 -29
- data/ext/common/agents/LoggingAgent/Main.cpp +43 -16
- data/ext/common/agents/LoggingAgent/RemoteSender.h +7 -7
- data/ext/common/agents/Watchdog/AgentWatcher.cpp +11 -11
- data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +3 -1
- data/ext/common/agents/Watchdog/Main.cpp +62 -0
- data/ext/libeio/config.guess +206 -167
- data/ext/libeio/config.sub +142 -68
- data/ext/libev/config.guess +304 -290
- data/ext/libev/config.sub +198 -77
- data/ext/nginx/config +4 -0
- data/ext/nginx/ngx_http_passenger_module.c +1 -0
- data/ext/oxt/implementation.cpp +4 -4
- data/lib/phusion_passenger.rb +14 -5
- data/lib/phusion_passenger/abstract_installer.rb +41 -0
- data/lib/phusion_passenger/admin_tools/server_instance.rb +48 -39
- data/lib/phusion_passenger/message_client.rb +31 -7
- data/lib/phusion_passenger/native_support.rb +35 -12
- data/lib/phusion_passenger/packaging.rb +16 -2
- data/lib/phusion_passenger/platform_info/binary_compatibility.rb +6 -31
- data/lib/phusion_passenger/platform_info/operating_system.rb +1 -1
- data/lib/phusion_passenger/preloader_shared_helpers.rb +3 -1
- data/lib/phusion_passenger/request_handler.rb +1 -1
- data/lib/phusion_passenger/standalone/command.rb +6 -6
- data/lib/phusion_passenger/standalone/main.rb +23 -8
- data/lib/phusion_passenger/standalone/package_runtime_command.rb +9 -5
- data/lib/phusion_passenger/standalone/runtime_installer.rb +9 -10
- data/lib/phusion_passenger/standalone/start_command.rb +20 -4
- data/resources/templates/installer_common/freebsd9_broken_cxx_runtime.txt.erb +19 -0
- data/resources/templates/installer_common/low_amount_of_memory_warning.txt.erb +22 -0
- data/resources/templates/standalone/config.erb +3 -2
- data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +4 -4
- data/test/cxx/ApplicationPool2/PoolTest.cpp +1 -1
- data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +7 -7
- data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +9 -9
- data/test/cxx/EventedBufferedInputTest.cpp +17 -17
- data/test/cxx/RequestHandlerTest.cpp +5 -5
- data/test/cxx/ServerInstanceDirTest.cpp +3 -1
- data/test/cxx/TestSupport.h +4 -4
- data/test/cxx/UnionStationTest.cpp +3 -1
- data/test/cxx/UtilsTest.cpp +2 -0
- data/test/integration_tests/apache2_tests.rb +2 -2
- data/test/integration_tests/native_packaging_spec.rb +170 -0
- data/test/ruby/spec_helper.rb +0 -1
- data/test/stub/apache2/httpd.conf.erb +1 -1
- data/test/stub/nginx/nginx.conf.erb +1 -0
- data/test/support/apache2_controller.rb +1 -1
- data/test/support/placebo-preloader.rb +1 -1
- data/test/support/test_helper.rb +5 -2
- metadata +32 -26
- metadata.gz.asc +7 -7
- data/debian/compat +0 -1
- data/debian/control +0 -49
- data/debian/copyright +0 -20
- data/debian/libapache2-mod-passenger.install +0 -1
- data/debian/passenger-common.install +0 -4
- data/debian/passenger.conf +0 -4
- data/debian/prerm +0 -2
- data/debian/rules +0 -37
- data/debian/watch +0 -3
- data/dev/googlecode_upload.py +0 -265
- data/ext/common/agents/HelperAgent/BacktracesServer.h +0 -60
- data/resources/templates/nginx/not_available_when_natively_packaged.txt.erb +0 -8
- data/test/stub/rails3.1/app/assets/javascripts/application.js +0 -9
- data/test/stub/rails3.2/app/assets/javascripts/application.js +0 -15
- data/test/stub/rails_apps/2.3/mycook/public/javascripts/application.js +0 -2
- data/test/stub/rails_apps/2.3/mycook/public/javascripts/controls.js +0 -963
- data/test/stub/rails_apps/2.3/mycook/public/javascripts/dragdrop.js +0 -973
- data/test/stub/rails_apps/2.3/mycook/public/javascripts/effects.js +0 -1128
- data/test/stub/rails_apps/2.3/mycook/public/javascripts/prototype.js +0 -4320
data/ext/common/Account.h
CHANGED
@@ -62,7 +62,7 @@ public:
|
|
62
62
|
ALL = ~0,
|
63
63
|
NONE = 0,
|
64
64
|
|
65
|
-
//
|
65
|
+
// ApplicationPool2::Server rights.
|
66
66
|
GET = 1 << 0,
|
67
67
|
CLEAR = 1 << 1,
|
68
68
|
DETACH = 1 << 2,
|
@@ -73,8 +73,9 @@ public:
|
|
73
73
|
//INSPECT_BACKEND_ADDRESSES = 1 << 6,
|
74
74
|
//INSPECT_DETACH_KEYS = 1 << 7,
|
75
75
|
|
76
|
-
//
|
77
|
-
|
76
|
+
// HelperAgent admin rights.
|
77
|
+
INSPECT_REQUESTS = 1 << 8,
|
78
|
+
INSPECT_BACKTRACES = 1 << 9,
|
78
79
|
|
79
80
|
// Other rights.
|
80
81
|
EXIT = 1 << 31
|
@@ -60,7 +60,7 @@ public:
|
|
60
60
|
}
|
61
61
|
|
62
62
|
unsigned int size() const {
|
63
|
-
lock_guard<boost::mutex> l(lock);
|
63
|
+
boost::lock_guard<boost::mutex> l(lock);
|
64
64
|
return (unsigned int) accounts.size();
|
65
65
|
}
|
66
66
|
|
@@ -76,13 +76,13 @@ public:
|
|
76
76
|
|
77
77
|
AccountPtr add(const string &username, const string &passwordOrHash, bool hashGiven, int rights = Account::ALL) {
|
78
78
|
AccountPtr account(new Account(username, passwordOrHash, hashGiven, rights));
|
79
|
-
lock_guard<boost::mutex> l(lock);
|
79
|
+
boost::lock_guard<boost::mutex> l(lock);
|
80
80
|
accounts[username] = account;
|
81
81
|
return account;
|
82
82
|
}
|
83
83
|
|
84
84
|
const AccountPtr get(const string &username) const {
|
85
|
-
lock_guard<boost::mutex> l(lock);
|
85
|
+
boost::lock_guard<boost::mutex> l(lock);
|
86
86
|
map<string, AccountPtr>::const_iterator it = accounts.find(username);
|
87
87
|
if (it == accounts.end()) {
|
88
88
|
return AccountPtr();
|
@@ -92,7 +92,7 @@ public:
|
|
92
92
|
}
|
93
93
|
|
94
94
|
AccountPtr authenticate(const string &username, const StaticString &userSuppliedPassword) const {
|
95
|
-
lock_guard<boost::mutex> l(lock);
|
95
|
+
boost::lock_guard<boost::mutex> l(lock);
|
96
96
|
map<string, AccountPtr>::const_iterator it = accounts.find(username);
|
97
97
|
if (it == accounts.end()) {
|
98
98
|
return AccountPtr();
|
@@ -107,7 +107,7 @@ public:
|
|
107
107
|
}
|
108
108
|
|
109
109
|
bool remove(const string &username) {
|
110
|
-
lock_guard<boost::mutex> l(lock);
|
110
|
+
boost::lock_guard<boost::mutex> l(lock);
|
111
111
|
map<string, AccountPtr>::iterator it = accounts.find(username);
|
112
112
|
if (it == accounts.end()) {
|
113
113
|
return false;
|
@@ -118,7 +118,7 @@ public:
|
|
118
118
|
}
|
119
119
|
|
120
120
|
unsigned int getUniqueNumber() {
|
121
|
-
lock_guard<boost::mutex> l(lock);
|
121
|
+
boost::lock_guard<boost::mutex> l(lock);
|
122
122
|
unsigned int result = uniqueNumber;
|
123
123
|
uniqueNumber++;
|
124
124
|
return result;
|
data/ext/common/AgentsStarter.h
CHANGED
@@ -269,17 +269,6 @@ private:
|
|
269
269
|
}
|
270
270
|
return false;
|
271
271
|
}
|
272
|
-
|
273
|
-
string findUnionStationGatewayCert(const ResourceLocator &locator,
|
274
|
-
const VariantMap ¶ms) const
|
275
|
-
{
|
276
|
-
string value = params.get("union_station_gateway_cert", false);
|
277
|
-
if (value.empty()) {
|
278
|
-
return locator.getResourcesDir() + "/union_station_gateway.crt";
|
279
|
-
} else {
|
280
|
-
return value;
|
281
|
-
}
|
282
|
-
}
|
283
272
|
|
284
273
|
public:
|
285
274
|
/**
|
@@ -391,7 +380,6 @@ public:
|
|
391
380
|
this_thread::disable_interruption di;
|
392
381
|
this_thread::disable_syscall_interruption dsi;
|
393
382
|
ResourceLocator locator(passengerRoot);
|
394
|
-
string realUnionStationGatewayCert = findUnionStationGatewayCert(locator, extraParams);
|
395
383
|
string watchdogFilename = locator.getAgentsDir() + "/PassengerWatchdog";
|
396
384
|
SocketPair fds;
|
397
385
|
int e;
|
@@ -586,7 +574,7 @@ public:
|
|
586
574
|
UPDATE_TRACE_POINT();
|
587
575
|
killProcessGroupAndWait(&pid, 5000);
|
588
576
|
guard.clear();
|
589
|
-
throw RuntimeException("
|
577
|
+
throw RuntimeException("The Phusion Passenger watchdog sent an unknown feedback message '" + args[0] + "'");
|
590
578
|
}
|
591
579
|
}
|
592
580
|
}
|
@@ -116,14 +116,14 @@ private:
|
|
116
116
|
string agentsDir = resourceLocator.getAgentsDir();
|
117
117
|
vector<string> command;
|
118
118
|
|
119
|
-
split(options.getStartCommand(resourceLocator), '\
|
119
|
+
split(options.getStartCommand(resourceLocator), '\t', startCommandArgs);
|
120
120
|
if (startCommandArgs.empty()) {
|
121
121
|
throw RuntimeException("No startCommand given");
|
122
122
|
}
|
123
123
|
|
124
|
-
if (options
|
125
|
-
command.push_back(
|
126
|
-
command.push_back(
|
124
|
+
if (shouldLoadShellEnvvars(options, preparation)) {
|
125
|
+
command.push_back(preparation.shell);
|
126
|
+
command.push_back(preparation.shell);
|
127
127
|
command.push_back("-lc");
|
128
128
|
command.push_back("exec \"$@\"");
|
129
129
|
command.push_back("SpawnPreparerShell");
|
@@ -61,7 +61,7 @@ public:
|
|
61
61
|
sockets->add("main", "tcp://127.0.0.1:1234", "session", config->concurrency);
|
62
62
|
syscalls::usleep(config->spawnTime);
|
63
63
|
|
64
|
-
lock_guard<boost::mutex> l(lock);
|
64
|
+
boost::lock_guard<boost::mutex> l(lock);
|
65
65
|
count++;
|
66
66
|
ProcessPtr process = make_shared<Process>(SafeLibevPtr(),
|
67
67
|
(pid_t) count, "gupid-" + toString(count),
|
@@ -184,6 +184,7 @@ private:
|
|
184
184
|
void wakeUpGarbageCollector();
|
185
185
|
bool poolAtFullCapacity() const;
|
186
186
|
bool anotherGroupIsWaitingForCapacity() const;
|
187
|
+
const ResourceLocator &getResourceLocator() const;
|
187
188
|
|
188
189
|
void verifyInvariants() const {
|
189
190
|
// !a || b: logical equivalent of a IMPLIES b.
|
@@ -514,7 +515,7 @@ private:
|
|
514
515
|
postLockActions.push_back(boost::bind(interruptAndJoinAllThreads,
|
515
516
|
shared_from_this()));
|
516
517
|
{
|
517
|
-
lock_guard<boost::mutex> l(lifetimeSyncher);
|
518
|
+
boost::lock_guard<boost::mutex> l(lifetimeSyncher);
|
518
519
|
lifeStatus = SHUT_DOWN;
|
519
520
|
}
|
520
521
|
selfPointer.reset();
|
@@ -668,7 +669,7 @@ public:
|
|
668
669
|
selfPointer = shared_from_this();
|
669
670
|
assert(disableWaitlist.empty());
|
670
671
|
{
|
671
|
-
lock_guard<boost::mutex> l(lifetimeSyncher);
|
672
|
+
boost::lock_guard<boost::mutex> l(lifetimeSyncher);
|
672
673
|
lifeStatus = SHUTTING_DOWN;
|
673
674
|
}
|
674
675
|
}
|
@@ -766,13 +767,13 @@ public:
|
|
766
767
|
|
767
768
|
// Thread-safe.
|
768
769
|
bool isAlive() const {
|
769
|
-
lock_guard<boost::mutex> lock(lifetimeSyncher);
|
770
|
+
boost::lock_guard<boost::mutex> lock(lifetimeSyncher);
|
770
771
|
return lifeStatus == ALIVE;
|
771
772
|
}
|
772
773
|
|
773
774
|
// Thread-safe.
|
774
775
|
LifeStatus getLifeStatus() const {
|
775
|
-
lock_guard<boost::mutex> lock(lifetimeSyncher);
|
776
|
+
boost::lock_guard<boost::mutex> lock(lifetimeSyncher);
|
776
777
|
return lifeStatus;
|
777
778
|
}
|
778
779
|
|
@@ -1080,6 +1081,10 @@ public:
|
|
1080
1081
|
P_BUG("Unknown 'lifeStatus' state " << (int) lifeStatus);
|
1081
1082
|
}
|
1082
1083
|
|
1084
|
+
stream << "<options>";
|
1085
|
+
options.toXml(stream, getResourceLocator());
|
1086
|
+
stream << "</options>";
|
1087
|
+
|
1083
1088
|
stream << "<processes>";
|
1084
1089
|
|
1085
1090
|
for (it = enabledProcesses.begin(); it != enabledProcesses.end(); it++) {
|
@@ -1042,6 +1042,11 @@ Group::anotherGroupIsWaitingForCapacity() const {
|
|
1042
1042
|
return false;
|
1043
1043
|
}
|
1044
1044
|
|
1045
|
+
const ResourceLocator &
|
1046
|
+
Group::getResourceLocator() const {
|
1047
|
+
return getPool()->spawnerFactory->getResourceLocator();
|
1048
|
+
}
|
1049
|
+
|
1045
1050
|
string
|
1046
1051
|
Group::generateSecret(const SuperGroupPtr &superGroup) {
|
1047
1052
|
return superGroup->getPool()->randomGenerator->generateAsciiString(43);
|
@@ -1117,7 +1122,7 @@ PipeWatcher::initialize() {
|
|
1117
1122
|
|
1118
1123
|
void
|
1119
1124
|
PipeWatcher::start() {
|
1120
|
-
lock_guard<boost::mutex> lock(startSyncher);
|
1125
|
+
boost::lock_guard<boost::mutex> lock(startSyncher);
|
1121
1126
|
started = true;
|
1122
1127
|
startCond.notify_all();
|
1123
1128
|
}
|
@@ -35,6 +35,7 @@
|
|
35
35
|
#include <Constants.h>
|
36
36
|
#include <ResourceLocator.h>
|
37
37
|
#include <StaticString.h>
|
38
|
+
#include <Utils.h>
|
38
39
|
|
39
40
|
namespace Passenger {
|
40
41
|
namespace ApplicationPool2 {
|
@@ -172,7 +173,7 @@ public:
|
|
172
173
|
StaticString appType;
|
173
174
|
|
174
175
|
/** The command for spawning the application process. This is a list of
|
175
|
-
* arguments, separated by '\
|
176
|
+
* arguments, separated by '\t', e.g. "ruby\tfoo.rb". Only used
|
176
177
|
* during spawning and only if appType.empty(). */
|
177
178
|
StaticString startCommand;
|
178
179
|
|
@@ -479,46 +480,73 @@ public:
|
|
479
480
|
logger.reset();
|
480
481
|
return *this;
|
481
482
|
}
|
483
|
+
|
484
|
+
enum FieldSet {
|
485
|
+
SPAWN_OPTIONS = 1 << 0,
|
486
|
+
PER_GROUP_POOL_OPTIONS = 1 << 1,
|
487
|
+
ALL_OPTIONS = ~0
|
488
|
+
};
|
482
489
|
|
483
490
|
/**
|
484
|
-
* Append
|
485
|
-
*
|
491
|
+
* Append information in this Options object to the given string vector, except
|
492
|
+
* for environmentVariables. You can customize what information you want through
|
493
|
+
* the `elements` argument.
|
486
494
|
*/
|
487
|
-
void toVector(vector<string> &vec, const ResourceLocator &resourceLocator
|
488
|
-
|
489
|
-
|
495
|
+
void toVector(vector<string> &vec, const ResourceLocator &resourceLocator,
|
496
|
+
int fields = ALL_OPTIONS) const
|
497
|
+
{
|
498
|
+
if (fields & SPAWN_OPTIONS) {
|
499
|
+
appendKeyValue (vec, "app_root", appRoot);
|
500
|
+
appendKeyValue (vec, "app_group_name", getAppGroupName());
|
501
|
+
appendKeyValue (vec, "app_type", appType);
|
502
|
+
appendKeyValue (vec, "start_command", getStartCommand(resourceLocator));
|
503
|
+
appendKeyValue (vec, "startup_file", getStartupFile());
|
504
|
+
appendKeyValue (vec, "process_title", getProcessTitle());
|
505
|
+
appendKeyValue2(vec, "log_level", logLevel);
|
506
|
+
appendKeyValue3(vec, "start_timeout", startTimeout);
|
507
|
+
appendKeyValue (vec, "environment", environment);
|
508
|
+
appendKeyValue (vec, "base_uri", baseURI);
|
509
|
+
appendKeyValue (vec, "spawn_method", spawnMethod);
|
510
|
+
appendKeyValue (vec, "user", user);
|
511
|
+
appendKeyValue (vec, "group", group);
|
512
|
+
appendKeyValue (vec, "default_user", defaultUser);
|
513
|
+
appendKeyValue (vec, "default_group", defaultGroup);
|
514
|
+
appendKeyValue (vec, "restart_dir", restartDir);
|
515
|
+
appendKeyValue (vec, "preexec_chroot", preexecChroot);
|
516
|
+
appendKeyValue (vec, "postexec_chroot", postexecChroot);
|
517
|
+
appendKeyValue (vec, "ruby", ruby);
|
518
|
+
appendKeyValue (vec, "python", python);
|
519
|
+
appendKeyValue (vec, "logging_agent_address", loggingAgentAddress);
|
520
|
+
appendKeyValue (vec, "logging_agent_username", loggingAgentUsername);
|
521
|
+
appendKeyValue (vec, "logging_agent_password", loggingAgentPassword);
|
522
|
+
appendKeyValue4(vec, "debugger", debugger);
|
523
|
+
appendKeyValue4(vec, "analytics", analytics);
|
524
|
+
appendKeyValue (vec, "union_station_key", unionStationKey);
|
525
|
+
|
526
|
+
appendKeyValue (vec, "group_secret", groupSecret);
|
527
|
+
}
|
528
|
+
if (fields & PER_GROUP_POOL_OPTIONS) {
|
529
|
+
appendKeyValue3(vec, "min_processes", minProcesses);
|
530
|
+
appendKeyValue2(vec, "max_preloader_idle_time", maxPreloaderIdleTime);
|
490
531
|
}
|
491
|
-
|
492
|
-
appendKeyValue (vec, "app_root", appRoot);
|
493
|
-
appendKeyValue (vec, "app_group_name", getAppGroupName());
|
494
|
-
appendKeyValue (vec, "app_type", appType);
|
495
|
-
appendKeyValue (vec, "start_command", getStartCommand(resourceLocator));
|
496
|
-
appendKeyValue (vec, "process_title", getProcessTitle());
|
497
|
-
appendKeyValue2(vec, "log_level", logLevel);
|
498
|
-
appendKeyValue3(vec, "start_timeout", startTimeout);
|
499
|
-
appendKeyValue (vec, "environment", environment);
|
500
|
-
appendKeyValue (vec, "base_uri", baseURI);
|
501
|
-
appendKeyValue (vec, "spawn_method", spawnMethod);
|
502
|
-
appendKeyValue (vec, "user", user);
|
503
|
-
appendKeyValue (vec, "group", group);
|
504
|
-
appendKeyValue (vec, "default_user", defaultUser);
|
505
|
-
appendKeyValue (vec, "default_group", defaultGroup);
|
506
|
-
appendKeyValue (vec, "restart_dir", restartDir);
|
507
|
-
appendKeyValue (vec, "preexec_chroot", preexecChroot);
|
508
|
-
appendKeyValue (vec, "postexec_chroot", postexecChroot);
|
509
|
-
appendKeyValue (vec, "ruby", ruby);
|
510
|
-
appendKeyValue (vec, "python", python);
|
511
|
-
appendKeyValue (vec, "logging_agent_address", loggingAgentAddress);
|
512
|
-
appendKeyValue (vec, "logging_agent_username", loggingAgentUsername);
|
513
|
-
appendKeyValue (vec, "logging_agent_password", loggingAgentPassword);
|
514
|
-
appendKeyValue4(vec, "debugger", debugger);
|
515
|
-
appendKeyValue4(vec, "analytics", analytics);
|
516
|
-
appendKeyValue (vec, "union_station_key", unionStationKey);
|
517
|
-
|
518
|
-
appendKeyValue (vec, "group_secret", groupSecret);
|
519
532
|
|
520
533
|
/*********************************/
|
521
534
|
}
|
535
|
+
|
536
|
+
template<typename Stream>
|
537
|
+
void toXml(Stream &stream, const ResourceLocator &resourceLocator,
|
538
|
+
int fields = ALL_OPTIONS) const
|
539
|
+
{
|
540
|
+
vector<string> args;
|
541
|
+
unsigned int i;
|
542
|
+
|
543
|
+
toVector(args, resourceLocator, fields);
|
544
|
+
for (i = 0; i < args.size(); i += 2) {
|
545
|
+
stream << "<" << args[i] << ">";
|
546
|
+
stream << escapeForXml(args[i + 1]);
|
547
|
+
stream << "</" << args[i] << ">";
|
548
|
+
}
|
549
|
+
}
|
522
550
|
|
523
551
|
/**
|
524
552
|
* Returns the app group name. If there is no explicitly set app group name
|
@@ -534,11 +562,11 @@ public:
|
|
534
562
|
|
535
563
|
string getStartCommand(const ResourceLocator &resourceLocator) const {
|
536
564
|
if (appType == "classic-rails") {
|
537
|
-
return ruby + "\
|
565
|
+
return ruby + "\t" + resourceLocator.getHelperScriptsDir() + "/classic-rails-loader.rb";
|
538
566
|
} else if (appType == "rack") {
|
539
|
-
return ruby + "\
|
567
|
+
return ruby + "\t" + resourceLocator.getHelperScriptsDir() + "/rack-loader.rb";
|
540
568
|
} else if (appType == "wsgi") {
|
541
|
-
return python + "\
|
569
|
+
return python + "\t" + resourceLocator.getHelperScriptsDir() + "/wsgi-loader.py";
|
542
570
|
} else {
|
543
571
|
return startCommand;
|
544
572
|
}
|
@@ -529,6 +529,12 @@ public:
|
|
529
529
|
return superGroups.get(options.getAppGroupName()).get();
|
530
530
|
}
|
531
531
|
|
532
|
+
struct GarbageCollectorState {
|
533
|
+
unsigned long long now;
|
534
|
+
unsigned long long nextGcRunTime;
|
535
|
+
vector<Callback> actions;
|
536
|
+
};
|
537
|
+
|
532
538
|
static void garbageCollect(PoolPtr self) {
|
533
539
|
TRACE_POINT();
|
534
540
|
{
|
@@ -551,13 +557,53 @@ public:
|
|
551
557
|
}
|
552
558
|
}
|
553
559
|
|
560
|
+
void maybeUpdateNextGcRuntime(GarbageCollectorState &state, unsigned long candidate) {
|
561
|
+
if (state.nextGcRunTime == 0 || candidate < state.nextGcRunTime) {
|
562
|
+
state.nextGcRunTime = candidate;
|
563
|
+
}
|
564
|
+
}
|
565
|
+
|
566
|
+
void maybeDetachIdleProcess(GarbageCollectorState &state, const GroupPtr &group,
|
567
|
+
const ProcessPtr &process, ProcessList::iterator &p_it)
|
568
|
+
{
|
569
|
+
assert(maxIdleTime > 0);
|
570
|
+
unsigned long long processGcTime =
|
571
|
+
process->lastUsed + maxIdleTime;
|
572
|
+
if (process->sessions == 0
|
573
|
+
&& state.now >= processGcTime
|
574
|
+
&& (unsigned long) group->enabledCount > group->options.minProcesses) {
|
575
|
+
ProcessList::iterator prev = p_it;
|
576
|
+
prev--;
|
577
|
+
P_DEBUG("Garbage collect idle process: " << process->inspect() <<
|
578
|
+
", group=" << group->name);
|
579
|
+
group->detach(process, state.actions);
|
580
|
+
p_it = prev;
|
581
|
+
} else {
|
582
|
+
maybeUpdateNextGcRuntime(state, processGcTime);
|
583
|
+
}
|
584
|
+
}
|
585
|
+
|
586
|
+
void maybeCleanPreloader(GarbageCollectorState &state, const GroupPtr &group) {
|
587
|
+
if (group->spawner->cleanable() && group->options.getMaxPreloaderIdleTime() != 0) {
|
588
|
+
unsigned long long spawnerGcTime =
|
589
|
+
group->spawner->lastUsed() +
|
590
|
+
group->options.getMaxPreloaderIdleTime() * 1000000;
|
591
|
+
if (state.now >= spawnerGcTime) {
|
592
|
+
P_DEBUG("Garbage collect idle spawner: group=" << group->name);
|
593
|
+
group->cleanupSpawner(state.actions);
|
594
|
+
} else {
|
595
|
+
maybeUpdateNextGcRuntime(state, spawnerGcTime);
|
596
|
+
}
|
597
|
+
}
|
598
|
+
}
|
599
|
+
|
554
600
|
unsigned long long realGarbageCollect() {
|
555
601
|
TRACE_POINT();
|
556
602
|
ScopedLock lock(syncher);
|
557
603
|
SuperGroupMap::iterator it, end = superGroups.end();
|
558
|
-
|
559
|
-
|
560
|
-
|
604
|
+
GarbageCollectorState state;
|
605
|
+
state.now = SystemTime::getUsec();
|
606
|
+
state.nextGcRunTime = 0;
|
561
607
|
|
562
608
|
P_DEBUG("Garbage collection time...");
|
563
609
|
verifyInvariants();
|
@@ -572,45 +618,22 @@ public:
|
|
572
618
|
|
573
619
|
for (g_it = groups.begin(); g_it != g_end; g_it++) {
|
574
620
|
GroupPtr group = *g_it;
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
process
|
584
|
-
if (process->sessions == 0
|
585
|
-
&& now >= processGcTime
|
586
|
-
&& (unsigned long) group->enabledCount > group->options.minProcesses) {
|
587
|
-
ProcessList::iterator prev = p_it;
|
588
|
-
prev--;
|
589
|
-
P_DEBUG("Garbage collect idle process: " << process->inspect() <<
|
590
|
-
", group=" << group->name);
|
591
|
-
group->detach(process, actions);
|
592
|
-
p_it = prev;
|
593
|
-
} else if (nextGcRunTime == 0
|
594
|
-
|| processGcTime < nextGcRunTime) {
|
595
|
-
nextGcRunTime = processGcTime;
|
621
|
+
|
622
|
+
if (maxIdleTime > 0) {
|
623
|
+
ProcessList &processes = group->enabledProcesses;
|
624
|
+
ProcessList::iterator p_it, p_end = processes.end();
|
625
|
+
|
626
|
+
for (p_it = processes.begin(); p_it != p_end; p_it++) {
|
627
|
+
ProcessPtr process = *p_it;
|
628
|
+
// ...detach processes that have been idle for more than maxIdleTime.
|
629
|
+
maybeDetachIdleProcess(state, group, process, p_it);
|
596
630
|
}
|
597
631
|
}
|
598
632
|
|
599
633
|
group->verifyInvariants();
|
600
|
-
|
634
|
+
|
601
635
|
// ...cleanup the spawner if it's been idle for more than preloaderIdleTime.
|
602
|
-
|
603
|
-
unsigned long long spawnerGcTime =
|
604
|
-
group->spawner->lastUsed() +
|
605
|
-
group->options.getMaxPreloaderIdleTime() * 1000000;
|
606
|
-
if (now >= spawnerGcTime) {
|
607
|
-
P_DEBUG("Garbage collect idle spawner: group=" << group->name);
|
608
|
-
group->cleanupSpawner(actions);
|
609
|
-
} else if (nextGcRunTime == 0
|
610
|
-
|| spawnerGcTime < nextGcRunTime) {
|
611
|
-
nextGcRunTime = spawnerGcTime;
|
612
|
-
}
|
613
|
-
}
|
636
|
+
maybeCleanPreloader(state, group);
|
614
637
|
}
|
615
638
|
|
616
639
|
superGroup->verifyInvariants();
|
@@ -621,22 +644,22 @@ public:
|
|
621
644
|
|
622
645
|
// Schedule next garbage collection run.
|
623
646
|
unsigned long long sleepTime;
|
624
|
-
if (nextGcRunTime == 0 || nextGcRunTime <= now) {
|
647
|
+
if (state.nextGcRunTime == 0 || state.nextGcRunTime <= state.now) {
|
625
648
|
if (maxIdleTime == 0) {
|
626
649
|
sleepTime = 10 * 60 * 1000000;
|
627
650
|
} else {
|
628
651
|
sleepTime = maxIdleTime;
|
629
652
|
}
|
630
653
|
} else {
|
631
|
-
sleepTime = nextGcRunTime - now;
|
654
|
+
sleepTime = state.nextGcRunTime - state.now;
|
632
655
|
}
|
633
656
|
P_DEBUG("Garbage collection done; next garbage collect in " <<
|
634
657
|
std::fixed << std::setprecision(3) << (sleepTime / 1000000.0) << " sec");
|
635
658
|
|
636
659
|
UPDATE_TRACE_POINT();
|
637
|
-
runAllActions(actions);
|
660
|
+
runAllActions(state.actions);
|
638
661
|
UPDATE_TRACE_POINT();
|
639
|
-
actions.clear();
|
662
|
+
state.actions.clear();
|
640
663
|
return sleepTime;
|
641
664
|
}
|
642
665
|
|
@@ -1182,6 +1205,18 @@ public:
|
|
1182
1205
|
return ProcessPtr();
|
1183
1206
|
}
|
1184
1207
|
|
1208
|
+
ProcessPtr findProcessByPid(pid_t pid, bool lock = true) const {
|
1209
|
+
vector<ProcessPtr> processes = getProcesses(lock);
|
1210
|
+
vector<ProcessPtr>::const_iterator it, end = processes.end();
|
1211
|
+
for (it = processes.begin(); it != end; it++) {
|
1212
|
+
const ProcessPtr &process = *it;
|
1213
|
+
if (process->pid == pid) {
|
1214
|
+
return process;
|
1215
|
+
}
|
1216
|
+
}
|
1217
|
+
return ProcessPtr();
|
1218
|
+
}
|
1219
|
+
|
1185
1220
|
bool detachSuperGroupByName(const string &name) {
|
1186
1221
|
TRACE_POINT();
|
1187
1222
|
ScopedLock l(syncher);
|
@@ -1261,6 +1296,21 @@ public:
|
|
1261
1296
|
return result;
|
1262
1297
|
}
|
1263
1298
|
|
1299
|
+
bool detachProcess(pid_t pid) {
|
1300
|
+
ScopedLock l(syncher);
|
1301
|
+
ProcessPtr process = findProcessByPid(pid, false);
|
1302
|
+
if (process != NULL) {
|
1303
|
+
vector<Callback> actions;
|
1304
|
+
bool result = detachProcessUnlocked(process, actions);
|
1305
|
+
fullVerifyInvariants();
|
1306
|
+
l.unlock();
|
1307
|
+
runAllActions(actions);
|
1308
|
+
return result;
|
1309
|
+
} else {
|
1310
|
+
return false;
|
1311
|
+
}
|
1312
|
+
}
|
1313
|
+
|
1264
1314
|
bool detachProcess(const string &gupid) {
|
1265
1315
|
ScopedLock l(syncher);
|
1266
1316
|
ProcessPtr process = findProcessByGupid(gupid, false);
|