From 6c297a038a60f21356d4dc6bbfedd8ad49a34731 Mon Sep 17 00:00:00 2001 From: Owais Lone Date: Mon, 25 Jul 2016 00:45:47 +0530 Subject: [PATCH] Added ability timeout when waiting for webpack to compile a bundle --- .gitignore | 2 ++ Makefile | 29 +++++++++++++++++++++++++++++ README.md | 9 ++++++++- requirements-dev.txt | 1 + tests/app/tests/test_webpack.py | 15 +++++++++++++-- tests/db.sqlite3 | Bin 3072 -> 36864 bytes webpack_loader/__init__.py | 2 +- webpack_loader/config.py | 1 + webpack_loader/exceptions.py | 4 ++++ webpack_loader/loader.py | 23 +++++++++++++++++++---- 10 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 Makefile create mode 100644 requirements-dev.txt diff --git a/.gitignore b/.gitignore index 71b0596f..8cd66792 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +venv/ + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..e29f651d --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +.PHONY: clean build deploy install publish + +# Project settings +PROJECT = webpack-loader + +# Virtual environment settings +ENV ?= venv + +requirements = -r requirements-dev.txt + +# List directories +dist_dir = dist +clean_dirs = $(PROJECT) $(ENV) $(tests_dir) $(shell [ -d $(tox_dir) ] && echo $(tox_dir) || :) + +all: install build + +clean: + find webpack_loader/ -name '*.pyc' -delete + rm -rf ./build ./*egg* ./.coverage + +build: clean + python setup.py sdist bdist_wheel --universal + +install: + [ ! -d $(ENV)/ ] && virtualenv $(ENV)/ || : + $(ENV)/bin/pip install $(requirements) + +publish: build + $(ENV)/bin/twine upload dist/* diff --git a/README.md b/README.md index 6fe029c2..4f2c1cff 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,7 @@ WEBPACK_LOADER = { 'BUNDLE_DIR_NAME': 'bundles/', # must end with slash 'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'), 'POLL_INTERVAL': 0.1, + 'TIMEOUT': None, 'IGNORE': ['.+\.hot-update.js', '.+\.map'] } } @@ -147,12 +148,18 @@ and your webpack config is located at `/home/src/webpack.config.js`, then the va #### POLL_INTERVAL -`POLL_INTERVAL` is the number of seconds webpack_loader should wait between polling the stats file. The stats file is polled every 200 miliseconds by default and any requests to are blocked while webpack compiles the bundles. You can reduce this if your bundles take shorter to compile. +`POLL_INTERVAL` is the number of seconds webpack_loader should wait between polling the stats file. The stats file is polled every 100 miliseconds by default and any requests to are blocked while webpack compiles the bundles. You can reduce this if your bundles take shorter to compile. **NOTE:** Stats file is not polled when in production (DEBUG=False).
+#### TIMEOUT + +`TIMEOUT` is the number of seconds webpack_loader should wait for webpack to finish compiling before raising an exception. `0`, `None` or leaving the value out of settings disables timeouts. + +
+ ## Usage
diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 00000000..b314c8c1 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1 @@ +twine==1.7.4 diff --git a/tests/app/tests/test_webpack.py b/tests/app/tests/test_webpack.py index 0b6a85f6..337de78f 100644 --- a/tests/app/tests/test_webpack.py +++ b/tests/app/tests/test_webpack.py @@ -12,7 +12,8 @@ from unittest2 import skipIf from webpack_loader.exceptions import ( WebpackError, - WebpackLoaderBadStatsError + WebpackLoaderBadStatsError, + WebpackLoaderTimeoutError ) from webpack_loader.utils import get_loader @@ -146,7 +147,6 @@ def test_jinja2(self): self.assertIn('', result.rendered_content) def test_reporting_errors(self): - #TODO: self.compile_bundles('webpack.config.error.js') try: get_loader(DEFAULT_CONFIG).get_bundle('main') @@ -166,6 +166,17 @@ def test_missing_stats_file(self): ).format(stats_file) self.assertIn(expected, str(e)) + def test_timeouts(self): + with self.settings(DEBUG=True): + with open( + settings.WEBPACK_LOADER[DEFAULT_CONFIG]['STATS_FILE'], 'w' + ) as stats_file: + stats_file.write(json.dumps({'status': 'compiling'})) + loader = get_loader(DEFAULT_CONFIG) + loader.config['TIMEOUT'] = 0.1 + with self.assertRaises(WebpackLoaderTimeoutError): + loader.get_bundle('main') + def test_bad_status_in_production(self): with open( settings.WEBPACK_LOADER[DEFAULT_CONFIG]['STATS_FILE'], 'w' diff --git a/tests/db.sqlite3 b/tests/db.sqlite3 index 755e4629edd976e84eea2b0c0f155ecf4546c793..61d68fda96767d3cca428fe294ff4ea143718493 100644 GIT binary patch literal 36864 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 UohK$YDm1@xX43B`_kAe;2TYF2od5s; delta 59 zcmZozz| start): + timed_out = True assets = self.get_assets() + if timed_out: + raise WebpackLoaderTimeoutError( + "Timed Out. Bundle `{0}` took more than {1} seconds " + "to compile.".format(bundle_name, timeout) + ) + if assets.get('status') == 'done': chunks = assets['chunks'][bundle_name] return self.filter_chunks(chunks)