From a5051054eed3f342c126d9a6bf8f63a624a69e13 Mon Sep 17 00:00:00 2001 From: Eric Joanis Date: Wed, 5 Feb 2025 15:25:51 -0500 Subject: [PATCH] perf: cache the bundles after we fetched them once (#260) * perf: cache the bundles once we fetched them once * test: better test coverage for bundle caching * test: exercise the path where network times out --- readalongs/text/make_package.py | 37 ++++++++++++++++++++------------- test/test_api.py | 33 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/readalongs/text/make_package.py b/readalongs/text/make_package.py index 69105310..53a13a63 100644 --- a/readalongs/text/make_package.py +++ b/readalongs/text/make_package.py @@ -150,6 +150,10 @@ def fetch_bundle_file(url, filename, prev_status_code): _prev_js_status_code: Any = None _prev_fonts_status_code: Any = None +# Cache the bundle contents so we don't fetch it more than once when running a process +# that might generate several HTML files via the API, e.g., the EveryVoice demo app. +js_bundle_contents = None +fonts_bundle_contents = None def create_web_component_html( @@ -160,24 +164,29 @@ def create_web_component_html( subheader=DEFAULT_SUBHEADER, theme="light", ) -> str: - global _prev_js_status_code - _prev_js_status_code, js_raw = fetch_bundle_file( - JS_BUNDLE_URL, "bundle.js", _prev_js_status_code - ) - - global _prev_fonts_status_code - if _prev_fonts_status_code is None and _prev_js_status_code != 200: - # If fetching bundle.js failed, don't bother trying bundle.css - _prev_fonts_status_code = _prev_js_status_code - _prev_fonts_status_code, fonts_raw = fetch_bundle_file( - FONTS_BUNDLE_URL, "bundle.css", _prev_fonts_status_code - ) + global js_bundle_contents + if js_bundle_contents is None: + global _prev_js_status_code + _prev_js_status_code, js_bundle_contents = fetch_bundle_file( + JS_BUNDLE_URL, "bundle.js", _prev_js_status_code + ) + js_bundle_contents = js_bundle_contents + + global fonts_bundle_contents + if fonts_bundle_contents is None: + global _prev_fonts_status_code + if _prev_fonts_status_code is None and _prev_js_status_code != 200: + # If fetching bundle.js failed, don't bother trying bundle.css + _prev_fonts_status_code = _prev_js_status_code + _prev_fonts_status_code, fonts_bundle_contents = fetch_bundle_file( + FONTS_BUNDLE_URL, "bundle.css", _prev_fonts_status_code + ) return BASIC_HTML.format( ras=encode_from_path(ras_path), audio=encode_from_path(audio_path), - js=js_raw, - fonts=fonts_raw, + js=js_bundle_contents, + fonts=fonts_bundle_contents, title=title, header=header, subheader=subheader, diff --git a/test/test_api.py b/test/test_api.py index 70a1bfdc..d3779b00 100755 --- a/test/test_api.py +++ b/test/test_api.py @@ -155,6 +155,13 @@ def test_convert_to_readalong(self): self.assertEqual(readalong, align_result) def test_convert_to_offline_html(self): + import readalongs.text.make_package as make_package + + # We want to exercise caching of the bundles, but first we need to uncache + # them in case some other test case already cached them. + make_package.fonts_bundle_contents = None + make_package.js_bundle_contents = None + html, _ = api.convert_prealigned_text_to_offline_html( self.sentences_to_convert, str(self.data_dir / "noise.mp3"), @@ -171,6 +178,32 @@ def test_convert_to_offline_html(self): self.assertIn("", html) self.assertIn("by Jove!", html) + # Make sure the bundles got cached + self.assertIsNotNone(make_package.fonts_bundle_contents) + self.assertIsNotNone(make_package.js_bundle_contents) + + # And convert again, this time it's going to use the cached bundles. + html2, _ = api.convert_prealigned_text_to_offline_html( + self.sentences_to_convert, + str(self.data_dir / "noise.mp3"), + subheader="by Jove!", + ) + self.assertEqual(html, html2) + + # Once more, this time pretend we could not fetch the first bundle + make_package.fonts_bundle_contents = None + make_package.js_bundle_contents = None + make_package._prev_js_status_code = "TIMEOUT" + make_package._prev_fonts_status_code = None + _, _ = api.convert_prealigned_text_to_offline_html( + self.sentences_to_convert, + str(self.data_dir / "noise.mp3"), + subheader="by Jove!", + ) + self.assertEqual(make_package._prev_fonts_status_code, "TIMEOUT") + self.assertIsNotNone(make_package.fonts_bundle_contents) + self.assertIsNotNone(make_package.js_bundle_contents) + if __name__ == "__main__": main()