<h3 dir="auto">Expected Behavior</h3>
<p dir="auto">auto_pop of the request context should be executed regardless of whether an exception happened after pushing the context(for example, when opening a session).</p>
<p dir="auto">We're using Redis sessions from flask_session:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="def _setup_session(app):
    from util.cache.region import cache_region
    from dogpile.cache.backends.null import NullBackend
    from flask_session import RedisSessionInterface

    if not isinstance(cache_region.backend, NullBackend):
        redis = cache_region.backend.client
        session_interface = RedisSessionInterface(redis, 'test.session.', use_signer=False, permanent=False)
        app.session_interface = session_interface"><pre class="notranslate"><span class="pl-k">def</span> <span class="pl-en">_setup_session</span>(<span class="pl-s1">app</span>):
    <span class="pl-k">from</span> <span class="pl-s1">util</span>.<span class="pl-s1">cache</span>.<span class="pl-s1">region</span> <span class="pl-k">import</span> <span class="pl-s1">cache_region</span>
    <span class="pl-k">from</span> <span class="pl-s1">dogpile</span>.<span class="pl-s1">cache</span>.<span class="pl-s1">backends</span>.<span class="pl-s1">null</span> <span class="pl-k">import</span> <span class="pl-v">NullBackend</span>
    <span class="pl-k">from</span> <span class="pl-s1">flask_session</span> <span class="pl-k">import</span> <span class="pl-v">RedisSessionInterface</span>

    <span class="pl-k">if</span> <span class="pl-c1">not</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">cache_region</span>.<span class="pl-s1">backend</span>, <span class="pl-v">NullBackend</span>):
        <span class="pl-s1">redis</span> <span class="pl-c1">=</span> <span class="pl-s1">cache_region</span>.<span class="pl-s1">backend</span>.<span class="pl-s1">client</span>
        <span class="pl-s1">session_interface</span> <span class="pl-c1">=</span> <span class="pl-v">RedisSessionInterface</span>(<span class="pl-s1">redis</span>, <span class="pl-s">'test.session.'</span>, <span class="pl-s1">use_signer</span><span class="pl-c1">=</span><span class="pl-c1">False</span>, <span class="pl-s1">permanent</span><span class="pl-c1">=</span><span class="pl-c1">False</span>)
        <span class="pl-s1">app</span>.<span class="pl-s1">session_interface</span> <span class="pl-c1">=</span> <span class="pl-s1">session_interface</span></pre></div>
<h3 dir="auto">Actual Behavior</h3>
<p dir="auto">The request context is not popped whenever there is a timeout getting the session from Redis.<br>
We can see in following requests the 'g' object still holds information from the failing request.</p>
<p dir="auto">In ctx.py the context is first pushed and then the session is opened:</p>
<div class="highlight highlight-text-python-traceback notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="        _request_ctx_stack.push(self)

        # Open the session at the moment that the request context is
        # available. This allows a custom open_session method to use the
        # request context (e.g. code that access database information
        # stored on `g` instead of the appcontext).
        self.session = self.app.open_session(self.request)"><pre class="notranslate">        _request_ctx_stack.push(<span class="pl-c1">self</span>)

        <span class="pl-c"><span class="pl-c">#</span> Open the session at the moment that the request context is</span>
        <span class="pl-c"><span class="pl-c">#</span> available. This allows a custom open_session method to use the</span>
        <span class="pl-c"><span class="pl-c">#</span> request context (e.g. code that access database information</span>
        <span class="pl-c"><span class="pl-c">#</span> stored on `g` instead of the appcontext).</span>
        <span class="pl-c1">self</span>.session <span class="pl-k">=</span> <span class="pl-c1">self</span>.app.open_session(<span class="pl-c1">self</span>.request)</pre></div>
<p dir="auto">But if open_session() fails, then ctx.auto_pop() is not executed. Perhaps ctx.push() should also be under the try...finally block in app.py?</p>
<p dir="auto">This is the exception that triggers the context not to be popped:</p>
<div class="highlight highlight-text-python-traceback notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="redis.exceptions:TimeoutError: Timeout reading from socket
Traceback (most recent call last):
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/newrelic-2.74.0.54/newrelic/api/web_transaction.py&quot;, line 738, in __iter__
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/newrelic-2.74.0.54/newrelic/api/web_transaction.py&quot;, line 1114, in __call__
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/werkzeug/contrib/fixers.py&quot;, line 152, in __call__
File &quot;/var/www/censored_production/www/censored/util/logging.py&quot;, line 136, in __call__
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/flask/app.py&quot;, line 1813, in wsgi_app
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/flask/ctx.py&quot;, line 321, in push
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/flask/app.py&quot;, line 825, in open_session
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/flask_session/sessions.py&quot;, line 132, in open_session
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/newrelic-2.74.0.54/newrelic/hooks/datastore_redis.py&quot;, line 67, in _nr_wrapper_Redis_method_
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/redis/client.py&quot;, line 880, in get
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/redis/client.py&quot;, line 573, in execute_command
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/redis/client.py&quot;, line 585, in parse_response
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/redis/connection.py&quot;, line 577, in read_response
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/redis/connection.py&quot;, line 238, in read_response
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/redis/connection.py&quot;, line 168, in readline
File &quot;/var/www/censored_production/env/lib/python2.7/site-packages/redis/connection.py&quot;, line 139, in _read_from_socket"><pre class="notranslate">redis.exceptions:TimeoutError: Timeout reading from socket
Traceback (most recent call last):
File "/var/www/censored_production/env/lib/python2.7/site-packages/newrelic-2.74.0.54/newrelic/api/web_transaction.py", line 738, in __iter__
File "/var/www/censored_production/env/lib/python2.7/site-packages/newrelic-2.74.0.54/newrelic/api/web_transaction.py", line 1114, in __call__
File "/var/www/censored_production/env/lib/python2.7/site-packages/werkzeug/contrib/fixers.py", line 152, in __call__
File "/var/www/censored_production/www/censored/util/logging.py", line 136, in __call__
File "/var/www/censored_production/env/lib/python2.7/site-packages/flask/app.py", line 1813, in wsgi_app
File "/var/www/censored_production/env/lib/python2.7/site-packages/flask/ctx.py", line 321, in push
File "/var/www/censored_production/env/lib/python2.7/site-packages/flask/app.py", line 825, in open_session
File "/var/www/censored_production/env/lib/python2.7/site-packages/flask_session/sessions.py", line 132, in open_session
File "/var/www/censored_production/env/lib/python2.7/site-packages/newrelic-2.74.0.54/newrelic/hooks/datastore_redis.py", line 67, in _nr_wrapper_Redis_method_
File "/var/www/censored_production/env/lib/python2.7/site-packages/redis/client.py", line 880, in get
File "/var/www/censored_production/env/lib/python2.7/site-packages/redis/client.py", line 573, in execute_command
File "/var/www/censored_production/env/lib/python2.7/site-packages/redis/client.py", line 585, in parse_response
File "/var/www/censored_production/env/lib/python2.7/site-packages/redis/connection.py", line 577, in read_response
File "/var/www/censored_production/env/lib/python2.7/site-packages/redis/connection.py", line 238, in read_response
File "/var/www/censored_production/env/lib/python2.7/site-packages/redis/connection.py", line 168, in readline
File "/var/www/censored_production/env/lib/python2.7/site-packages/redis/connection.py", line 139, in _read_from_socket</pre></div>
<h3 dir="auto">Environment</h3>
<ul dir="auto">
<li>Python version: 2.7.6</li>
<li>Flask version: 0.10.1</li>
<li>Werkzeug version: 0.11.11</li>
</ul>
<p dir="auto">RequestContext push is called in <a href="https://github.com/mitsuhiko/flask/blob/master/flask/app.py#L1952">wsgi_app method</a>, outside try..finally block. In <a href="https://github.com/mitsuhiko/flask/blob/master/flask/ctx.py#L332">push() method</a> application's open_session call takes place, which can possibly lead to exception. But, since original call is not in try..finally block, removal of stack top never takes place. This leads to following problems:</p>
<h3 dir="auto">1. Application context stack never updates again</h3>
<p dir="auto">RequestContext.push() only <a href="https://github.com/mitsuhiko/flask/blob/master/flask/ctx.py#L316">checks</a> that application context exists or belongs to current application, but same rules apply to previous context.</p>
<h3 dir="auto">2. Request context stack grows</h3>
<p dir="auto">Again, request context stack is pushed, but never removed. Actually just a memory leak :)</p>
<h3 dir="auto">3. Misleading code comment about open_session usage</h3>
<p dir="auto">Inspired by <a href="https://github.com/mitsuhiko/flask/blob/master/flask/ctx.py#L328">this comment</a>, i started to develop multi-tenant application, and found nothing but disappointment. <strong>You can't actually access request_context before open_session interface call.</strong> This means, you can't configure which database to use before opening a session.</p>
<h2 dir="auto">My proposition.</h2>
<p dir="auto">Move open_session call to full_dispatch_request, and add interfaces and methods, similar to before_request - before_open_session, or call before_request before opening session (may break code that depends on session interface)</p>