diff --git a/flask/app.py b/flask/app.py index c3170df6..cc3fc1d9 100644 --- a/flask/app.py +++ b/flask/app.py @@ -1492,9 +1492,9 @@ class Flask(_PackageBoundObject): with self._before_request_lock: if self._got_first_request: return - self._got_first_request = True for func in self.before_first_request_funcs: func() + self._got_first_request = True def make_default_options_response(self): """This method is called to create the default `OPTIONS` response. diff --git a/flask/testsuite/basic.py b/flask/testsuite/basic.py index 1858ca5c..8399a607 100644 --- a/flask/testsuite/basic.py +++ b/flask/testsuite/basic.py @@ -16,6 +16,7 @@ import pickle import unittest from datetime import datetime from threading import Thread +from time import sleep from flask.testsuite import FlaskTestCase, emits_module_deprecation_warning from flask._compat import text_type from werkzeug.exceptions import BadRequest, NotFound @@ -1015,6 +1016,23 @@ class BasicFunctionalityTestCase(FlaskTestCase): self.assert_equal(got, [42]) self.assert_true(app.got_first_request) + def test_before_first_request_functions_concurrent(self): + got = [] + app = flask.Flask(__name__) + @app.before_first_request + def foo(): + sleep(1) + got.append(42) + c = app.test_client() + def get_and_assert(): + c.get("/") + self.assert_equal(got, [42]) + t = Thread(target=get_and_assert) + t.start() + get_and_assert() + t.join() + self.assert_true(app.got_first_request) + def test_routing_redirect_debugging(self): app = flask.Flask(__name__) app.debug = True