passenger 3.9.2.beta → 4.0.0.rc4
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/.travis.yml +3 -0
- data/NEWS +77 -7
- data/README.md +3 -11
- data/bin/passenger-install-apache2-module +24 -20
- data/bin/passenger-install-nginx-module +25 -23
- data/build/agents.rb +11 -0
- data/build/apache2.rb +9 -5
- data/build/basics.rb +37 -30
- data/build/common_library.rb +4 -1
- data/build/cplusplus_support.rb +5 -5
- data/build/cxx_tests.rb +28 -8
- data/build/integration_tests.rb +6 -3
- data/build/nginx.rb +3 -3
- data/build/packaging.rb +95 -57
- data/build/ruby_extension.rb +34 -21
- data/build/ruby_tests.rb +4 -2
- data/build/test_basics.rb +1 -1
- data/dev/run_travis.sh +36 -1
- data/doc/Users guide Apache.html +425 -308
- data/doc/Users guide Apache.idmap.txt +78 -70
- data/doc/Users guide Apache.index.sqlite3 +0 -0
- data/doc/Users guide Apache.txt +33 -92
- data/doc/Users guide Nginx.html +519 -220
- data/doc/Users guide Nginx.idmap.txt +78 -60
- data/doc/Users guide Nginx.txt +115 -26
- data/doc/Users guide Standalone.html +8 -2
- data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +1 -7
- data/doc/users_guide_snippets/installation.txt +167 -22
- data/doc/users_guide_snippets/rackup_specifications.txt +4 -0
- data/doc/users_guide_snippets/since_version.txt +1 -0
- data/doc/users_guide_snippets/support_information.txt +3 -7
- data/doc/users_guide_snippets/tips.txt +0 -24
- data/ext/apache2/Configuration.cpp +11 -33
- data/ext/apache2/Configuration.hpp +3 -18
- data/ext/apache2/DirectoryMapper.h +20 -70
- data/ext/apache2/Hooks.cpp +2 -2
- data/ext/common/AgentsStarter.cpp +0 -2
- data/ext/common/AgentsStarter.h +0 -1
- data/ext/common/AgentsStarter.hpp +1 -3
- data/ext/common/ApplicationPool2/AppTypes.cpp +74 -0
- data/ext/common/ApplicationPool2/AppTypes.h +202 -0
- data/ext/common/ApplicationPool2/Common.h +12 -10
- data/ext/common/ApplicationPool2/DirectSpawner.h +256 -0
- data/ext/common/ApplicationPool2/DummySpawner.h +90 -0
- data/ext/common/ApplicationPool2/Group.h +311 -94
- data/ext/common/ApplicationPool2/Implementation.cpp +405 -145
- data/ext/common/ApplicationPool2/Options.h +24 -26
- data/ext/common/ApplicationPool2/PipeWatcher.h +20 -13
- data/ext/common/ApplicationPool2/Pool.h +326 -183
- data/ext/common/ApplicationPool2/Process.h +205 -55
- data/ext/common/ApplicationPool2/README.md +1 -1
- data/ext/common/ApplicationPool2/Session.h +21 -10
- data/ext/common/ApplicationPool2/SmartSpawner.h +801 -0
- data/ext/common/ApplicationPool2/Spawner.h +141 -1149
- data/ext/common/ApplicationPool2/SpawnerFactory.h +132 -0
- data/ext/common/ApplicationPool2/SuperGroup.h +146 -223
- data/ext/common/Constants.h +4 -2
- data/ext/common/Exceptions.h +23 -1
- data/ext/common/Logging.cpp +17 -6
- data/ext/common/Logging.h +37 -7
- data/ext/common/ResourceLocator.h +1 -1
- data/ext/common/Utils.cpp +49 -1
- data/ext/common/Utils.h +13 -4
- data/ext/common/{AnsiColorConstants.h → Utils/AnsiColorConstants.h} +0 -0
- data/ext/common/{BCrypt.cpp → Utils/BCrypt.cpp} +0 -0
- data/ext/common/{BCrypt.h → Utils/BCrypt.h} +0 -0
- data/ext/common/{Blowfish.c → Utils/Blowfish.c} +0 -0
- data/ext/common/{Blowfish.h → Utils/Blowfish.h} +0 -0
- data/ext/common/Utils/CachedFileStat.hpp +27 -25
- data/ext/common/Utils/Curl.h +184 -0
- data/ext/common/{HttpConstants.h → Utils/HttpConstants.h} +3 -0
- data/ext/common/Utils/IOUtils.cpp +6 -2
- data/ext/common/{IniFile.h → Utils/IniFile.h} +0 -0
- data/ext/common/Utils/LargeFiles.cpp +30 -0
- data/ext/common/Utils/LargeFiles.h +40 -0
- data/ext/common/Utils/StrIntUtils.cpp +72 -8
- data/ext/common/Utils/StrIntUtils.h +24 -2
- data/ext/common/Utils/StringMap.h +12 -2
- data/ext/common/Utils/VariantMap.h +51 -2
- data/ext/common/Utils/jsoncpp.cpp +1 -1
- data/ext/common/agents/Base.cpp +147 -11
- data/ext/common/agents/HelperAgent/AgentOptions.h +14 -6
- data/ext/common/agents/HelperAgent/Main.cpp +79 -19
- data/ext/common/agents/HelperAgent/RequestHandler.h +36 -16
- data/ext/common/agents/LoggingAgent/LoggingServer.h +3 -5
- data/ext/common/agents/LoggingAgent/Main.cpp +2 -4
- data/ext/common/agents/LoggingAgent/RemoteSender.h +18 -24
- data/ext/common/agents/SpawnPreparer.cpp +7 -0
- data/ext/common/agents/Watchdog/Main.cpp +96 -38
- data/ext/nginx/Configuration.c +26 -22
- data/ext/nginx/Configuration.h +4 -2
- data/ext/nginx/ContentHandler.c +23 -52
- data/ext/nginx/ContentHandler.h +5 -11
- data/ext/nginx/config +10 -3
- data/ext/nginx/ngx_http_passenger_module.c +21 -6
- data/ext/nginx/ngx_http_passenger_module.h +4 -1
- data/ext/oxt/dynamic_thread_group.hpp +9 -1
- data/ext/oxt/system_calls.cpp +2 -2
- data/ext/ruby/extconf.rb +2 -1
- data/helper-scripts/backtrace-sanitizer.rb +2 -0
- data/helper-scripts/wsgi-loader.py +54 -21
- data/lib/phusion_passenger.rb +5 -3
- data/lib/phusion_passenger/abstract_installer.rb +18 -41
- data/lib/phusion_passenger/admin_tools/memory_stats.rb +2 -2
- data/lib/phusion_passenger/admin_tools/server_instance.rb +2 -2
- data/lib/phusion_passenger/common_library.rb +23 -3
- data/lib/phusion_passenger/debug_logging.rb +10 -3
- data/lib/phusion_passenger/packaging.rb +1 -0
- data/lib/phusion_passenger/platform_info.rb +113 -115
- data/lib/phusion_passenger/platform_info/compiler.rb +224 -134
- data/lib/phusion_passenger/platform_info/cxx_portability.rb +143 -0
- data/lib/phusion_passenger/platform_info/depcheck.rb +371 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +124 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +97 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/gems.rb +39 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/libs.rb +118 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/ruby.rb +137 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/utilities.rb +15 -0
- data/lib/phusion_passenger/platform_info/operating_system.rb +6 -5
- data/lib/phusion_passenger/platform_info/ruby.rb +45 -34
- data/lib/phusion_passenger/request_handler.rb +35 -22
- data/lib/phusion_passenger/request_handler/thread_handler.rb +5 -6
- data/lib/phusion_passenger/ruby_core_enhancements.rb +7 -1
- data/lib/phusion_passenger/standalone/runtime_installer.rb +43 -34
- data/lib/phusion_passenger/utils/robust_interruption.rb +34 -18
- data/passenger.gemspec +25 -0
- data/resources/templates/standalone/config.erb +3 -1
- data/test/config.json.travis +2 -2
- data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +37 -5
- data/test/cxx/ApplicationPool2/PoolTest.cpp +143 -50
- data/test/cxx/ApplicationPool2/ProcessTest.cpp +8 -0
- data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +28 -17
- data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +31 -26
- data/test/cxx/RequestHandlerTest.cpp +17 -1
- data/test/cxx/UtilsTest.cpp +84 -10
- data/test/integration_tests/apache2_tests.rb +49 -163
- data/test/integration_tests/hello_world_wsgi_spec.rb +2 -2
- data/test/integration_tests/mycook_spec.rb +1 -1
- data/test/integration_tests/nginx_tests.rb +37 -19
- data/test/ruby/request_handler_spec.rb +1 -0
- data/test/ruby/spec_helper.rb +52 -1
- data/test/stub/nginx/nginx.conf.erb +2 -0
- data/test/stub/rack/start.rb +5 -0
- data/test/stub/rails3.0/Gemfile.lock +30 -30
- data/test/stub/rails3.1/Gemfile +1 -1
- data/test/stub/rails3.1/Gemfile.lock +3 -3
- data/test/stub/rails3.2/Gemfile +1 -1
- data/test/stub/rails3.2/Gemfile.lock +4 -4
- data/test/stub/rails_apps/2.3/mycook/app/controllers/welcome_controller.rb +1 -1
- data/test/stub/rails_apps/2.3/mycook/app/helpers/recipes_helper.rb +2 -0
- data/test/stub/rails_apps/2.3/mycook/app/helpers/test_helper.rb +2 -0
- data/test/stub/rails_apps/2.3/mycook/app/helpers/uploads_helper.rb +2 -0
- data/test/stub/rails_apps/2.3/mycook/app/helpers/welcome_helper.rb +2 -0
- data/test/support/nginx_controller.rb +2 -1
- metadata +160 -156
- data/build/gempackagetask.rb +0 -99
- data/build/packagetask.rb +0 -186
- data/ext/common/StringListCreator.h +0 -83
- data/lib/phusion_passenger/dependencies.rb +0 -657
@@ -35,11 +35,13 @@ namespace tut {
|
|
35
35
|
createServerInstanceDirAndGeneration(serverInstanceDir, generation);
|
36
36
|
retainSessions = false;
|
37
37
|
spawnerConfig = make_shared<SpawnerConfig>();
|
38
|
-
spawnerFactory = make_shared<SpawnerFactory>(bg.safe, *resourceLocator,
|
39
|
-
|
38
|
+
spawnerFactory = make_shared<SpawnerFactory>(bg.safe, *resourceLocator,
|
39
|
+
generation, spawnerConfig);
|
40
40
|
pool = make_shared<Pool>(bg.safe.get(), spawnerFactory);
|
41
|
+
pool->initialize();
|
41
42
|
bg.start();
|
42
43
|
callback = boost::bind(&ApplicationPool2_PoolTest::_callback, this, _1, _2);
|
44
|
+
setLogLevel(LVL_ERROR); // TODO: change to LVL_WARN
|
43
45
|
}
|
44
46
|
|
45
47
|
~ApplicationPool2_PoolTest() {
|
@@ -47,12 +49,12 @@ namespace tut {
|
|
47
49
|
// additional code that depend on other fields in this
|
48
50
|
// class.
|
49
51
|
TRACE_POINT();
|
52
|
+
clearAllSessions();
|
53
|
+
UPDATE_TRACE_POINT();
|
50
54
|
pool->destroy();
|
51
55
|
UPDATE_TRACE_POINT();
|
52
56
|
pool.reset();
|
53
|
-
|
54
|
-
clearAllSessions();
|
55
|
-
setLogLevel(0);
|
57
|
+
setLogLevel(DEFAULT_LOG_LEVEL);
|
56
58
|
SystemTime::releaseAll();
|
57
59
|
}
|
58
60
|
|
@@ -559,6 +561,63 @@ namespace tut {
|
|
559
561
|
ensure_equals(currentSession->getProcess()->pid, 3);
|
560
562
|
ensure_equals(group->getWaitlist.size(), 0u);
|
561
563
|
}
|
564
|
+
|
565
|
+
TEST_METHOD(12) {
|
566
|
+
// Test shutting down.
|
567
|
+
ensureMinProcesses(2);
|
568
|
+
ensure(pool->detachSuperGroupByName("stub/rack"));
|
569
|
+
ensure_equals(pool->getSuperGroupCount(), 0u);
|
570
|
+
}
|
571
|
+
|
572
|
+
TEST_METHOD(13) {
|
573
|
+
// Test shutting down while Group is restarting.
|
574
|
+
initPoolDebugging();
|
575
|
+
debug->messages->send("Proceed with spawn loop iteration 1");
|
576
|
+
ensureMinProcesses(1);
|
577
|
+
|
578
|
+
ensure_equals(pool->restartGroupsByAppRoot("stub/rack"), 1u);
|
579
|
+
debug->debugger->recv("About to end restarting");
|
580
|
+
ensure(pool->detachSuperGroupByName("stub/rack"));
|
581
|
+
ensure_equals(pool->getSuperGroupCount(), 0u);
|
582
|
+
}
|
583
|
+
|
584
|
+
TEST_METHOD(14) {
|
585
|
+
// Test shutting down while Group is spawning.
|
586
|
+
initPoolDebugging();
|
587
|
+
Options options = createOptions();
|
588
|
+
|
589
|
+
pool->asyncGet(options, callback);
|
590
|
+
debug->debugger->recv("Begin spawn loop iteration 1");
|
591
|
+
ensure(pool->detachSuperGroupByName("stub/rack"));
|
592
|
+
ensure_equals(pool->getSuperGroupCount(), 0u);
|
593
|
+
}
|
594
|
+
|
595
|
+
TEST_METHOD(15) {
|
596
|
+
// Test shutting down while SuperGroup is initializing.
|
597
|
+
initPoolDebugging();
|
598
|
+
debug->spawning = false;
|
599
|
+
debug->superGroup = true;
|
600
|
+
Options options = createOptions();
|
601
|
+
|
602
|
+
pool->asyncGet(options, callback);
|
603
|
+
debug->debugger->recv("About to finish SuperGroup initialization");
|
604
|
+
ensure(pool->detachSuperGroupByName("stub/rack"));
|
605
|
+
ensure_equals(pool->getSuperGroupCount(), 0u);
|
606
|
+
}
|
607
|
+
|
608
|
+
TEST_METHOD(16) {
|
609
|
+
// Test shutting down while SuperGroup is restarting.
|
610
|
+
initPoolDebugging();
|
611
|
+
debug->spawning = false;
|
612
|
+
debug->superGroup = true;
|
613
|
+
debug->messages->send("Proceed with initializing SuperGroup");
|
614
|
+
ensureMinProcesses(1);
|
615
|
+
|
616
|
+
ensure_equals(pool->restartSuperGroupsByAppRoot("stub/rack"), 1u);
|
617
|
+
debug->debugger->recv("About to finish SuperGroup restart");
|
618
|
+
ensure(pool->detachSuperGroupByName("stub/rack"));
|
619
|
+
ensure_equals(pool->getSuperGroupCount(), 0u);
|
620
|
+
}
|
562
621
|
|
563
622
|
|
564
623
|
/*********** Test asyncGet() behavior on multiple SuperGroups,
|
@@ -598,7 +657,6 @@ namespace tut {
|
|
598
657
|
);
|
599
658
|
|
600
659
|
ensure_equals(pool->getProcessCount(), 2u);
|
601
|
-
ensure(!superGroup1->detached());
|
602
660
|
ensure_equals(superGroup1->getProcessCount(), 0u);
|
603
661
|
}
|
604
662
|
|
@@ -637,7 +695,6 @@ namespace tut {
|
|
637
695
|
);
|
638
696
|
|
639
697
|
ensure_equals(pool->getProcessCount(), 2u);
|
640
|
-
ensure(!superGroup1->detached());
|
641
698
|
ensure_equals(superGroup1->getProcessCount(), 0u);
|
642
699
|
}
|
643
700
|
|
@@ -665,8 +722,7 @@ namespace tut {
|
|
665
722
|
pool->asyncGet(options, callback);
|
666
723
|
{
|
667
724
|
LockGuard l(pool->syncher);
|
668
|
-
ensure("(1)",
|
669
|
-
ensure("(2)", !fooGroup->detached());
|
725
|
+
ensure("(1)", session1->getProcess()->isAlive());
|
670
726
|
ensure_equals("(3)", fooGroup->getWaitlist.size(), 1u);
|
671
727
|
}
|
672
728
|
|
@@ -676,8 +732,7 @@ namespace tut {
|
|
676
732
|
SessionPtr session3 = pool->get(options, &ticket);
|
677
733
|
{
|
678
734
|
LockGuard l(pool->syncher);
|
679
|
-
ensure("(4)", session1->getProcess()->
|
680
|
-
ensure("(5)", !fooGroup->detached());
|
735
|
+
ensure("(4)", !session1->getProcess()->isAlive());
|
681
736
|
ensure_equals("(6)", fooGroup->getWaitlist.size(), 1u);
|
682
737
|
ensure_equals("(7)", pool->getWaitlist.size(), 0u);
|
683
738
|
}
|
@@ -706,8 +761,9 @@ namespace tut {
|
|
706
761
|
result = number == 1;
|
707
762
|
);
|
708
763
|
|
764
|
+
ProcessPtr process = currentSession->getProcess();
|
709
765
|
pool->detachProcess(currentSession->getProcess());
|
710
|
-
ensure(
|
766
|
+
ensure(!process->isAlive());
|
711
767
|
EVENTUALLY(5,
|
712
768
|
result = pool->getProcessCount() == 2;
|
713
769
|
);
|
@@ -806,7 +862,7 @@ namespace tut {
|
|
806
862
|
pool->detachProcess(process);
|
807
863
|
LockGuard l(pool->syncher);
|
808
864
|
ensure_equals(pool->superGroups.size(), 1u);
|
809
|
-
ensure(
|
865
|
+
ensure(superGroup->isAlive());
|
810
866
|
ensure(!superGroup->garbageCollectable());
|
811
867
|
}
|
812
868
|
|
@@ -821,12 +877,12 @@ namespace tut {
|
|
821
877
|
pool->disableProcess(processes[0]->gupid), DR_SUCCESS);
|
822
878
|
|
823
879
|
LockGuard l(pool->syncher);
|
824
|
-
ensure(
|
880
|
+
ensure(processes[0]->isAlive());
|
825
881
|
ensure_equals("Process is disabled",
|
826
882
|
processes[0]->enabled,
|
827
883
|
Process::DISABLED);
|
828
884
|
ensure("Other processes are not affected",
|
829
|
-
|
885
|
+
processes[1]->isAlive());
|
830
886
|
ensure_equals("Other processes are not affected",
|
831
887
|
processes[1]->enabled, Process::ENABLED);
|
832
888
|
}
|
@@ -949,19 +1005,19 @@ namespace tut {
|
|
949
1005
|
}
|
950
1006
|
}
|
951
1007
|
|
952
|
-
// asyncGet() should not select a disabling process if there are enabled processes.
|
953
|
-
// asyncGet() should not select a disabling process when non-rolling restarting.
|
954
|
-
// asyncGet() should select a disabling process if there are no enabled processes
|
955
|
-
//
|
956
|
-
// asyncGet() should not select a disabled process.
|
1008
|
+
// TODO: asyncGet() should not select a disabling process if there are enabled processes.
|
1009
|
+
// TODO: asyncGet() should not select a disabling process when non-rolling restarting.
|
1010
|
+
// TODO: asyncGet() should select a disabling process if there are no enabled processes
|
1011
|
+
// in the group. If this happens then asyncGet() will also spawn a new process.
|
1012
|
+
// TODO: asyncGet() should not select a disabled process.
|
957
1013
|
|
958
|
-
// If there are no enabled processes and all disabling processes are at full
|
959
|
-
//
|
960
|
-
//
|
961
|
-
//
|
1014
|
+
// TODO: If there are no enabled processes and all disabling processes are at full
|
1015
|
+
// utilization, and the process that was being spawned becomes available
|
1016
|
+
// earlier than any of the disabling processes, then the newly spawned process
|
1017
|
+
// should handle the request.
|
962
1018
|
|
963
|
-
// A disabling process becomes disabled as soon as it's done with
|
964
|
-
//
|
1019
|
+
// TODO: A disabling process becomes disabled as soon as it's done with
|
1020
|
+
// all its request.
|
965
1021
|
|
966
1022
|
TEST_METHOD(50) {
|
967
1023
|
// Disabling a process that's already being disabled should result in the
|
@@ -983,9 +1039,9 @@ namespace tut {
|
|
983
1039
|
ensure_equals(code, (int) DR_SUCCESS);
|
984
1040
|
}
|
985
1041
|
|
986
|
-
// Enabling a process that's disabled succeeds immediately.
|
987
|
-
// Enabling a process that's disabling succeeds immediately. The disable
|
988
|
-
//
|
1042
|
+
// TODO: Enabling a process that's disabled succeeds immediately.
|
1043
|
+
// TODO: Enabling a process that's disabling succeeds immediately. The disable
|
1044
|
+
// callbacks will be called with DR_CANCELED.
|
989
1045
|
|
990
1046
|
|
991
1047
|
/*********** Other tests ***********/
|
@@ -1010,7 +1066,8 @@ namespace tut {
|
|
1010
1066
|
|
1011
1067
|
ensure_equals(pool->getProcessCount(), 2u);
|
1012
1068
|
ensure(pool->atFullCapacity());
|
1013
|
-
|
1069
|
+
clearAllSessions();
|
1070
|
+
pool->detachSuperGroupByName("test");
|
1014
1071
|
ensure(!pool->atFullCapacity());
|
1015
1072
|
}
|
1016
1073
|
|
@@ -1120,7 +1177,6 @@ namespace tut {
|
|
1120
1177
|
options.appRoot = "tmp.wsgi";
|
1121
1178
|
options.appType = "wsgi";
|
1122
1179
|
options.spawnMethod = "direct";
|
1123
|
-
ProcessPtr process;
|
1124
1180
|
pool->setMax(1);
|
1125
1181
|
|
1126
1182
|
// Send normal request.
|
@@ -1171,7 +1227,7 @@ namespace tut {
|
|
1171
1227
|
|
1172
1228
|
ensure(currentException != NULL);
|
1173
1229
|
shared_ptr<SpawnException> e = dynamic_pointer_cast<SpawnException>(currentException);
|
1174
|
-
|
1230
|
+
ensure(e->getErrorPage().find("Something went wrong!") != string::npos);
|
1175
1231
|
}
|
1176
1232
|
|
1177
1233
|
TEST_METHOD(68) {
|
@@ -1210,7 +1266,7 @@ namespace tut {
|
|
1210
1266
|
EVENTUALLY(5,
|
1211
1267
|
result = pool->getProcessCount() == 2;
|
1212
1268
|
);
|
1213
|
-
EVENTUALLY(
|
1269
|
+
EVENTUALLY(5,
|
1214
1270
|
result = !pool->isSpawning();
|
1215
1271
|
);
|
1216
1272
|
SHOULD_NEVER_HAPPEN(500,
|
@@ -1302,31 +1358,48 @@ namespace tut {
|
|
1302
1358
|
}
|
1303
1359
|
|
1304
1360
|
TEST_METHOD(72) {
|
1305
|
-
// If we restart while spawning is in progress,
|
1306
|
-
//
|
1361
|
+
// If we restart while spawning is in progress, and the restart
|
1362
|
+
// finishes before the process is done spawning, then that
|
1363
|
+
// process will not be attached and the original spawn loop will
|
1364
|
+
// abort. A new spawn loop will start to ensure that resource
|
1365
|
+
// constraints are met.
|
1307
1366
|
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
1308
1367
|
initPoolDebugging();
|
1309
1368
|
Options options = createOptions();
|
1310
1369
|
options.appRoot = "tmp.wsgi";
|
1311
1370
|
options.minProcesses = 3;
|
1312
1371
|
|
1313
|
-
// Trigger spawn loop and freeze it at the point where it's spawning
|
1372
|
+
// Trigger spawn loop and freeze it at the point where it's spawning
|
1373
|
+
// the second process.
|
1314
1374
|
pool->asyncGet(options, callback);
|
1315
1375
|
debug->debugger->recv("Begin spawn loop iteration 1");
|
1376
|
+
debug->messages->send("Proceed with spawn loop iteration 1");
|
1377
|
+
debug->debugger->recv("Begin spawn loop iteration 2");
|
1378
|
+
ensure_equals("(1)", pool->getProcessCount(), 1u);
|
1316
1379
|
|
1317
|
-
// Trigger restart,
|
1380
|
+
// Trigger restart, wait until it's finished.
|
1318
1381
|
touchFile("tmp.wsgi/tmp/restart.txt", 1);
|
1319
1382
|
pool->asyncGet(options, callback);
|
1320
|
-
debug->
|
1321
|
-
debug->
|
1383
|
+
debug->messages->send("Finish restarting");
|
1384
|
+
debug->debugger->recv("Restarting done");
|
1385
|
+
ensure_equals("(2)", pool->getProcessCount(), 0u);
|
1322
1386
|
|
1323
|
-
// The
|
1324
|
-
//
|
1325
|
-
|
1387
|
+
// The restarter should have created a new spawn loop and
|
1388
|
+
// instructed the old one to stop.
|
1389
|
+
debug->debugger->recv("Begin spawn loop iteration 3");
|
1390
|
+
|
1391
|
+
// We let the old spawn loop continue, which should drop
|
1392
|
+
// the second process and abort.
|
1393
|
+
debug->messages->send("Proceed with spawn loop iteration 2");
|
1326
1394
|
debug->debugger->recv("Spawn loop done");
|
1327
|
-
ensure_equals(
|
1328
|
-
|
1329
|
-
|
1395
|
+
ensure_equals("(3)", pool->getProcessCount(), 0u);
|
1396
|
+
|
1397
|
+
// We let the new spawn loop continue.
|
1398
|
+
debug->messages->send("Proceed with spawn loop iteration 3");
|
1399
|
+
debug->messages->send("Proceed with spawn loop iteration 4");
|
1400
|
+
debug->messages->send("Proceed with spawn loop iteration 5");
|
1401
|
+
debug->debugger->recv("Spawn loop done");
|
1402
|
+
ensure_equals("(4)", pool->getProcessCount(), 3u);
|
1330
1403
|
}
|
1331
1404
|
|
1332
1405
|
TEST_METHOD(73) {
|
@@ -1427,7 +1500,7 @@ namespace tut {
|
|
1427
1500
|
retainSessions = true;
|
1428
1501
|
pool->asyncGet(options, callback);
|
1429
1502
|
pool->asyncGet(options, callback);
|
1430
|
-
EVENTUALLY(
|
1503
|
+
EVENTUALLY(10,
|
1431
1504
|
result = number == 2;
|
1432
1505
|
);
|
1433
1506
|
ensure_equals(pool->getProcessCount(), 2u);
|
@@ -1446,10 +1519,30 @@ namespace tut {
|
|
1446
1519
|
}
|
1447
1520
|
}
|
1448
1521
|
|
1449
|
-
// Persistent connections.
|
1450
|
-
// If one closes the session before it has reached EOF, and process's maximum concurrency
|
1451
|
-
//
|
1452
|
-
//
|
1522
|
+
// TODO: Persistent connections.
|
1523
|
+
// TODO: If one closes the session before it has reached EOF, and process's maximum concurrency
|
1524
|
+
// has already been reached, then the pool should ping the process so that it can detect
|
1525
|
+
// when the session's connection has been released by the app.
|
1526
|
+
|
1527
|
+
|
1528
|
+
/*********** Test previously discovered bugs ***********/
|
1529
|
+
|
1530
|
+
TEST_METHOD(76) {
|
1531
|
+
// Test detaching, then restarting. This should not violate any invariants.
|
1532
|
+
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
1533
|
+
Options options = createOptions();
|
1534
|
+
options.appRoot = "tmp.wsgi";
|
1535
|
+
options.appType = "wsgi";
|
1536
|
+
options.spawnMethod = "direct";
|
1537
|
+
|
1538
|
+
SessionPtr session = pool->get(options, &ticket);
|
1539
|
+
string gupid = session->getProcess()->gupid;
|
1540
|
+
session.reset();
|
1541
|
+
pool->detachProcess(gupid);
|
1542
|
+
touchFile("tmp.wsgi/tmp/restart.txt", 1);
|
1543
|
+
pool->get(options, &ticket).reset();
|
1544
|
+
}
|
1545
|
+
|
1453
1546
|
|
1454
1547
|
/*****************************/
|
1455
1548
|
}
|
@@ -51,6 +51,8 @@ namespace tut {
|
|
51
51
|
ProcessPtr process = make_shared<Process>(bg.safe,
|
52
52
|
123, "", "", adminSocket[0],
|
53
53
|
errorPipe[0], sockets, 0, 0);
|
54
|
+
process->dummy = true;
|
55
|
+
process->requiresShutdown = false;
|
54
56
|
ensure_equals(process->utilization(), 0);
|
55
57
|
ensure(!process->atFullCapacity());
|
56
58
|
}
|
@@ -60,6 +62,8 @@ namespace tut {
|
|
60
62
|
ProcessPtr process = make_shared<Process>(bg.safe,
|
61
63
|
123, "", "", adminSocket[0],
|
62
64
|
errorPipe[0], sockets, 0, 0);
|
65
|
+
process->dummy = true;
|
66
|
+
process->requiresShutdown = false;
|
63
67
|
SessionPtr session = process->newSession();
|
64
68
|
SessionPtr session2 = process->newSession();
|
65
69
|
ensure_equals(process->sessions, 2);
|
@@ -75,6 +79,8 @@ namespace tut {
|
|
75
79
|
ProcessPtr process = make_shared<Process>(bg.safe,
|
76
80
|
123, "", "", adminSocket[0],
|
77
81
|
errorPipe[0], sockets, 0, 0);
|
82
|
+
process->dummy = true;
|
83
|
+
process->requiresShutdown = false;
|
78
84
|
|
79
85
|
// The first 3 newSession() commands check out an idle socket.
|
80
86
|
SessionPtr session1 = process->newSession();
|
@@ -118,6 +124,8 @@ namespace tut {
|
|
118
124
|
ProcessPtr process = make_shared<Process>(bg.safe,
|
119
125
|
123, "", "", adminSocket[0],
|
120
126
|
errorPipe[0], sockets, 0, 0);
|
127
|
+
process->dummy = true;
|
128
|
+
process->requiresShutdown = false;
|
121
129
|
vector<SessionPtr> sessions;
|
122
130
|
for (int i = 0; i < 9; i++) {
|
123
131
|
ensure(!process->atFullCapacity());
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#include <TestSupport.h>
|
2
|
-
#include <ApplicationPool2/
|
2
|
+
#include <ApplicationPool2/SmartSpawner.h>
|
3
3
|
#include <Logging.h>
|
4
4
|
#include <Utils/json.h>
|
5
5
|
#include <unistd.h>
|
@@ -16,15 +16,24 @@ namespace tut {
|
|
16
16
|
ServerInstanceDirPtr serverInstanceDir;
|
17
17
|
ServerInstanceDir::GenerationPtr generation;
|
18
18
|
BackgroundEventLoop bg;
|
19
|
+
ProcessPtr process;
|
20
|
+
PipeWatcher::DataCallback gatherOutput;
|
21
|
+
string gatheredOutput;
|
22
|
+
boost::mutex gatheredOutputSyncher;
|
19
23
|
|
20
24
|
ApplicationPool2_SmartSpawnerTest() {
|
21
25
|
createServerInstanceDirAndGeneration(serverInstanceDir, generation);
|
22
26
|
bg.start();
|
27
|
+
PipeWatcher::onData = PipeWatcher::DataCallback();
|
28
|
+
gatherOutput = boost::bind(&ApplicationPool2_SmartSpawnerTest::_gatherOutput, this, _1, _2);
|
29
|
+
setLogLevel(LVL_ERROR); // TODO: should be LVL_WARN
|
23
30
|
}
|
24
31
|
|
25
32
|
~ApplicationPool2_SmartSpawnerTest() {
|
26
|
-
setLogLevel(
|
33
|
+
setLogLevel(DEFAULT_LOG_LEVEL);
|
27
34
|
unlink("stub/wsgi/passenger_wsgi.pyc");
|
35
|
+
Process::maybeShutdown(process);
|
36
|
+
PipeWatcher::onData = PipeWatcher::DataCallback();
|
28
37
|
}
|
29
38
|
|
30
39
|
shared_ptr<SmartSpawner> createSpawner(const Options &options, bool exitImmediately = false) {
|
@@ -51,6 +60,11 @@ namespace tut {
|
|
51
60
|
options.loadShellEnvvars = false;
|
52
61
|
return options;
|
53
62
|
}
|
63
|
+
|
64
|
+
void _gatherOutput(const char *data, unsigned int size) {
|
65
|
+
lock_guard<boost::mutex> l(gatheredOutputSyncher);
|
66
|
+
gatheredOutput.append(data, size);
|
67
|
+
}
|
54
68
|
};
|
55
69
|
|
56
70
|
DEFINE_TEST_GROUP_WITH_LIMIT(ApplicationPool2_SmartSpawnerTest, 90);
|
@@ -65,7 +79,7 @@ namespace tut {
|
|
65
79
|
options.startCommand = "ruby\1" "start.rb";
|
66
80
|
options.startupFile = "start.rb";
|
67
81
|
shared_ptr<SmartSpawner> spawner = createSpawner(options);
|
68
|
-
spawner->spawn(options);
|
82
|
+
spawner->spawn(options)->shutdown();
|
69
83
|
|
70
84
|
kill(spawner->getPreloaderPid(), SIGTERM);
|
71
85
|
// Give it some time to exit.
|
@@ -73,7 +87,7 @@ namespace tut {
|
|
73
87
|
|
74
88
|
// No exception at next spawn.
|
75
89
|
setLogLevel(-1);
|
76
|
-
spawner->spawn(options);
|
90
|
+
spawner->spawn(options)->shutdown();
|
77
91
|
}
|
78
92
|
|
79
93
|
TEST_METHOD(81) {
|
@@ -86,7 +100,7 @@ namespace tut {
|
|
86
100
|
setLogLevel(-1);
|
87
101
|
shared_ptr<SmartSpawner> spawner = createSpawner(options, true);
|
88
102
|
try {
|
89
|
-
spawner->spawn(options);
|
103
|
+
spawner->spawn(options)->shutdown();
|
90
104
|
fail("SpawnException expected");
|
91
105
|
} catch (const SpawnException &) {
|
92
106
|
// Pass.
|
@@ -116,13 +130,12 @@ namespace tut {
|
|
116
130
|
spawner.getConfig()->forwardStderr = false;
|
117
131
|
|
118
132
|
try {
|
119
|
-
spawner.spawn(options);
|
133
|
+
spawner.spawn(options)->shutdown();
|
120
134
|
fail("SpawnException expected");
|
121
135
|
} catch (const SpawnException &e) {
|
122
136
|
ensure_equals(e.getErrorKind(),
|
123
137
|
SpawnException::PRELOADER_STARTUP_TIMEOUT);
|
124
|
-
|
125
|
-
"hello world\n");
|
138
|
+
ensure(e.getErrorPage().find("hello world\n") != string::npos);
|
126
139
|
}
|
127
140
|
}
|
128
141
|
|
@@ -148,13 +161,12 @@ namespace tut {
|
|
148
161
|
spawner.getConfig()->forwardStderr = false;
|
149
162
|
|
150
163
|
try {
|
151
|
-
spawner.spawn(options);
|
164
|
+
spawner.spawn(options)->shutdown();
|
152
165
|
fail("SpawnException expected");
|
153
166
|
} catch (const SpawnException &e) {
|
154
167
|
ensure_equals(e.getErrorKind(),
|
155
168
|
SpawnException::PRELOADER_STARTUP_PROTOCOL_ERROR);
|
156
|
-
|
157
|
-
"hello world\n");
|
169
|
+
ensure(e.getErrorPage().find("hello world\n") != string::npos);
|
158
170
|
}
|
159
171
|
}
|
160
172
|
|
@@ -180,7 +192,7 @@ namespace tut {
|
|
180
192
|
spawner.getConfig()->forwardStderr = false;
|
181
193
|
|
182
194
|
try {
|
183
|
-
spawner.spawn(options);
|
195
|
+
spawner.spawn(options)->shutdown();
|
184
196
|
fail("SpawnException expected");
|
185
197
|
} catch (const SpawnException &e) {
|
186
198
|
ensure(containsSubstring(e["envvars"], "PASSENGER_FOO=foo\n"));
|
@@ -191,11 +203,10 @@ namespace tut {
|
|
191
203
|
// Test that the spawned process can still write to its stderr
|
192
204
|
// after the SmartSpawner has been destroyed.
|
193
205
|
DeleteFileEventually d("tmp.output");
|
194
|
-
|
206
|
+
PipeWatcher::onData = gatherOutput;
|
195
207
|
Options options = createOptions();
|
196
208
|
options.appRoot = "stub/rack";
|
197
209
|
|
198
|
-
ProcessPtr process;
|
199
210
|
{
|
200
211
|
vector<string> preloaderCommand;
|
201
212
|
preloaderCommand.push_back("ruby");
|
@@ -205,9 +216,8 @@ namespace tut {
|
|
205
216
|
generation,
|
206
217
|
preloaderCommand,
|
207
218
|
options);
|
208
|
-
spawner.getConfig()->forwardStdoutTo = output;
|
209
|
-
spawner.getConfig()->forwardStderrTo = output;
|
210
219
|
process = spawner.spawn(options);
|
220
|
+
process->requiresShutdown = false;
|
211
221
|
}
|
212
222
|
|
213
223
|
SessionPtr session = process->newSession();
|
@@ -226,7 +236,8 @@ namespace tut {
|
|
226
236
|
shutdown(session->fd(), SHUT_WR);
|
227
237
|
readAll(session->fd());
|
228
238
|
EVENTUALLY(2,
|
229
|
-
|
239
|
+
lock_guard<boost::mutex> l(gatheredOutputSyncher);
|
240
|
+
result = gatheredOutput.find("hello world!\n") != string::npos;
|
230
241
|
);
|
231
242
|
}
|
232
243
|
}
|