Mercurial > p > roundup > code
changeset 6747:d32d43e4a5ba
wsgi can cache tracker instance enabled by feature flag.
Patch by Marcus Priesch caches a loaded tracker instance and reuse it
for future client sessions.
It is enabled by a feature flag in wsgi.py since it arrived during the
2.2.0 beta period.
The provided wsgi.py is modified to enable it. Testing is run with
flag enabled and disabled.
Ralf Schlatterbeck and Marcus tested it on one of their larger more
complex trackers and it sped up the response time to a client request
by a factor of 3 (270ms down to about 80-85ms).
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Sat, 02 Jul 2022 14:04:00 -0400 |
| parents | efa203f3c696 |
| children | 647f806d54b8 |
| files | CHANGES.txt doc/upgrading.txt frontends/wsgi.py roundup/cgi/wsgi_handler.py test/test_liveserver.py |
| diffstat | 5 files changed, 70 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/CHANGES.txt Sat Jul 02 13:52:52 2022 -0400 +++ b/CHANGES.txt Sat Jul 02 14:04:00 2022 -0400 @@ -176,6 +176,9 @@ i18n object is now also correctly set for the mail interface: previously the 'language' setting in the [mailgw] section seems to have been ignored. Thanks to Marcus Priesch for the patch. +- issue2551212 - speed up wsgi interface by caching the tracker + instance. Hidden behind a feature flag. See upgrading.txt for + details. (Marcus Priesch with feature flag by John Rouillard) 2021-07-13 2.1.0
--- a/doc/upgrading.txt Sat Jul 02 13:52:52 2022 -0400 +++ b/doc/upgrading.txt Sat Jul 02 14:04:00 2022 -0400 @@ -209,6 +209,25 @@ of ps or shell history. The new password will be encrypted using the default encryption method (usually pbkdf2). +Enable performance improvement for wsgi mode (optional) +------------------------------------------------------- + +There is an experimental wsgi performance improvement mode that caches +the loaded roundup instance. This eliminates disk reads that are +incurred on each connection. In one report it improves speed by a +factor of 2 to 3 times. To enable this you should add a feature flag +to your Roundup wsgi wrapper (see the file +``.../share/frontends/wsgi.py``) so it looks like:: + + feature_flags = { "cache_tracker": "" } + app = RequestDispatcher(tracker_home, feature_flags=feature_flags) + +to enable this mode. Note that this is experimental and was added +during the 2.2.0 beta period, so it is enabled using a feature flag. +If you use this and it works for you please followup with an email to +the roundup-users at lists.sourceforge.net mailing list so we can +enable it by default in a future release. + Migrating from 2.0.0 to 2.1.0 =============================
--- a/frontends/wsgi.py Sat Jul 02 13:52:52 2022 -0400 +++ b/frontends/wsgi.py Sat Jul 02 14:04:00 2022 -0400 @@ -12,5 +12,10 @@ # Set the path to tracker home. tracker_home = '/path/to/tracker' +# Enable the feature flag to speed up wsgi response by caching the +# Roundup tracker instance on startup. See upgrading.txt for +# more info. +feature_flags = { "cache_tracker": "" } + # Definition signature for app: app(environ, start_response): -app = RequestDispatcher(tracker_home) +app = RequestDispatcher(tracker_home= feature_flags=feature_flags)
--- a/roundup/cgi/wsgi_handler.py Sat Jul 02 13:52:52 2022 -0400 +++ b/roundup/cgi/wsgi_handler.py Sat Jul 02 14:04:00 2022 -0400 @@ -74,17 +74,24 @@ class RequestDispatcher(object): - def __init__(self, home, debug=False, timing=False, lang=None): + def __init__(self, home, debug=False, timing=False, lang=None, + feature_flags=None): assert os.path.isdir(home), '%r is not a directory' % (home,) self.home = home self.debug = debug self.timing = timing + self.feature_flags= feature_flags or {} + self.tracker = None if lang: self.translator = TranslationService.get_translation(lang, tracker_home=home) else: self.translator = None - self.preload() + + if "cache_tracker" in self.feature_flags: + self.tracker = roundup.instance.open(self.home, not self.debug) + else: + self.preload() def __call__(self, environ, start_response): """Initialize with `apache.Request` object""" @@ -116,8 +123,8 @@ else: form = BinaryFieldStorage(fp=environ['wsgi.input'], environ=environ) - with self.get_tracker() as tracker: - client = tracker.Client(tracker, request, environ, form, + if "cache_tracker" in self.feature_flags: + client = self.tracker.Client(self.tracker, request, environ, form, self.translator) try: client.main() @@ -125,6 +132,16 @@ request.start_response([('Content-Type', 'text/html')], 404) request.wfile.write(s2b('Not found: %s' % html_escape(client.path))) + else: + with self.get_tracker() as tracker: + client = tracker.Client(tracker, request, environ, form, + self.translator) + try: + client.main() + except roundup.cgi.client.NotFound: + request.start_response([('Content-Type', 'text/html')], 404) + request.wfile.write(s2b('Not found: %s' % + html_escape(client.path))) # all body data has been written using wfile return []
--- a/test/test_liveserver.py Sat Jul 02 13:52:52 2022 -0400 +++ b/test/test_liveserver.py Sat Jul 02 14:04:00 2022 -0400 @@ -38,7 +38,7 @@ _py3 = sys.version_info[0] > 2 @skip_requests -class SimpleTest(LiveServerTestCase): +class WsgiSetup(LiveServerTestCase): # have chicken and egg issue here. Need to encode the base_url # in the config file but we don't know it until after # the server is started and has read the config.ini. @@ -103,7 +103,8 @@ i18n.DOMAIN = cls.backup_domain def create_app(self): - '''The wsgi app to start''' + '''The wsgi app to start - no feature_flags set.''' + if _py3: return validator(RequestDispatcher(self.dirname)) else: @@ -112,6 +113,11 @@ return RequestDispatcher(self.dirname) +class BaseTestCases(WsgiSetup): + """Class with all tests to run against wsgi server. Is reused when + wsgi server is started with various feature flags + """ + def test_start_page(self): """ simple test that verifies that the server can serve a start page. """ @@ -973,4 +979,16 @@ self.assertEqual(r.status_code, 201) print(r.status_code) - +class TestFeatureFlagCacheTrackerOn(BaseTestCases, WsgiSetup): + """Class to run all test in BaseTestCases with the cache_tracker + feature flag enabled when starting the wsgi server + """ + def create_app(self): + '''The wsgi app to start with feature flag enabled''' + ff = { "cache_tracker": "" } + if _py3: + return validator(RequestDispatcher(self.dirname, feature_flags=ff)) + else: + # wsgiref/validator.py InputWrapper::readline is broke and + # doesn't support the max bytes to read argument. + return RequestDispatcher(self.dirname, feature_flags=ff)
