diff options
author | Max Romanov <max.romanov@nginx.com> | 2018-01-29 16:17:36 +0300 |
---|---|---|
committer | Max Romanov <max.romanov@nginx.com> | 2018-01-29 16:17:36 +0300 |
commit | 9cd4fdbdb78e035254e8094b5cff2155857ab764 (patch) | |
tree | 6de4ee721996740cbeda8647e11b8b2aa18e704f /test/test_python_procman.py | |
parent | a36babddef203d79dc37736661e1a042df4064f8 (diff) | |
download | unit-9cd4fdbdb78e035254e8094b5cff2155857ab764.tar.gz unit-9cd4fdbdb78e035254e8094b5cff2155857ab764.tar.bz2 |
Introducing extended app process management.
- Pre-fork 'processes.spare' application processes;
- fork more processes to keep 'processes.spare' idle processes;
- fork on-demand up to 'processes.max' count;
- scale down idle application processes above 'processes.spare' after
'processes.idle_timeout';
- number of concurrently started application processes also limited by
'processes.spare' (or 1, if spare is 0).
Diffstat (limited to '')
-rw-r--r-- | test/test_python_procman.py | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/test/test_python_procman.py b/test/test_python_procman.py new file mode 100644 index 00000000..5d2a5f50 --- /dev/null +++ b/test/test_python_procman.py @@ -0,0 +1,237 @@ +import os +import time +import unittest +import unit + +class TestUnitApplication(unit.TestUnitControl): + + def setUpClass(): + u = unit.TestUnit() + + u.check_modules('python') + u.check_version('0.3') + + def getWorkerCount(self): + n = 0 + for f in os.listdir(self.testdir): + if f.startswith('proctest.'): + n += 1 + + return n + + def getTestCode(self): + return """ +import atexit +import os + +fname = "%s.%%d" %% os.getpid() + +def remove_file(): + os.remove(fname) + +atexit.register(remove_file) + +open(fname, 'w') + +def application(env, start_response): + start_response('200 OK', [('Content-Type','text/html')]) + return [b'body'] + +""" % (self.testdir + '/proctest') + + + def test_python_prefork(self): + code, name = self.getTestCode(), 'py_app' + + self.python_application(name, code) + + self.conf({ + "listeners": { + "*:7080": { + "application": "app" + } + }, + "applications": { + "app": { + "type": "python", + "processes": 2, + "path": self.testdir + '/' + name, + "module": "wsgi" + } + } + }) + + self.assertEqual(self.getWorkerCount(), 2, 'python prefork 2 processes') + + self.get() + self.assertEqual(self.getWorkerCount(), 2, 'python prefork, still 2') + + self.conf('4', '/applications/app/processes') + + time.sleep(0.2) + + self.assertEqual(self.getWorkerCount(), 4, 'python prefork 4 processes') + + self.get() + self.assertEqual(self.getWorkerCount(), 4, 'python prefork, still 4') + + self.conf({ + "listeners": {}, + "applications": {} + }) + + time.sleep(0.2) + self.assertEqual(self.getWorkerCount(), 0, 'python stop all processes') + + time.sleep(2.2) + + + def test_python_ondemand(self): + code, name = self.getTestCode(), 'py_app' + + self.python_application(name, code) + + self.conf({ + "listeners": { + "*:7080": { + "application": "app" + } + }, + "applications": { + "app": { + "type": "python", + "processes": { + "spare": 0, + "max": 8, + "idle_timeout": 2 + }, + "path": self.testdir + '/' + name, + "module": "wsgi" + } + } + }) + + self.assertEqual(self.getWorkerCount(), 0, 'python on-demand') + + self.get() + self.assertEqual(self.getWorkerCount(), 1, 'python start on-demand') + + self.get() + self.assertEqual(self.getWorkerCount(), 1, 'python still 1') + + time.sleep(2.2) + self.assertEqual(self.getWorkerCount(), 0, 'python stop idle') + + self.conf({ + "listeners": {}, + "applications": {} + }) + + time.sleep(0.2) + self.assertEqual(self.getWorkerCount(), 0, 'python stop all processes') + + time.sleep(2.2) + + def test_python_scale_updown(self): + code, name = self.getTestCode(), 'py_app' + + self.python_application(name, code) + + self.conf({ + "listeners": { + "*:7080": { + "application": "app" + } + }, + "applications": { + "app": { + "type": "python", + "processes": { + "spare": 2, + "max": 8, + "idle_timeout": 2 + }, + "path": self.testdir + '/' + name, + "module": "wsgi" + } + } + }) + + self.assertEqual(self.getWorkerCount(), 2, 'python prefork 2') + + self.get() + time.sleep(0.2) + self.assertEqual(self.getWorkerCount(), 3, 'python keep 2 idle, 1 busy') + + self.get() + time.sleep(0.2) + self.assertEqual(self.getWorkerCount(), 3, 'python still 3') + + time.sleep(2.2) + self.assertEqual(self.getWorkerCount(), 2, 'python stop idle') + + self.get() + + time.sleep(0.5) + self.assertEqual(self.getWorkerCount(), 3, 'python keep 2 idle, 1 busy') + + self.conf({ + "listeners": {}, + "applications": {} + }) + + time.sleep(0.2) + self.assertEqual(self.getWorkerCount(), 0, 'python stop all processes') + + time.sleep(2.2) + + def test_python_reconfigure(self): + code, name = self.getTestCode(), 'py_app' + + self.python_application(name, code) + + self.conf({ + "listeners": { + "*:7080": { + "application": "app" + } + }, + "applications": { + "app": { + "type": "python", + "processes": { + "spare": 2, + "max": 6, + "idle_timeout": 2 + }, + "path": self.testdir + '/' + name, + "module": "wsgi" + } + } + }) + + self.assertEqual(self.getWorkerCount(), 2, 'python prefork 2') + + self.get() + time.sleep(0.2) + self.assertEqual(self.getWorkerCount(), 3, 'python keep 2 idle, 1 busy') + + self.conf('6', '/applications/app/processes/spare') + self.assertEqual(self.getWorkerCount(), 6, 'python prefork 6') + + self.get() + time.sleep(0.2) + self.assertEqual(self.getWorkerCount(), 6, 'python still 6') + + self.conf({ + "listeners": {}, + "applications": {} + }) + + time.sleep(0.2) + self.assertEqual(self.getWorkerCount(), 0, 'python stop all processes') + + time.sleep(2.2) + +if __name__ == '__main__': + unittest.main() |