matthewk
matthewk

Reputation: 1841

Can't modify session in Flask route that returns a stream

I need to be able to modify a session variable in a Flask route that returns a stream, but it isn't working. I'm sure I'm missing something obvious but I cannot see what it is. I've simplified and reduced the code as far as possible:

from flask import Flask, Response, render_template, session, stream_with_context
from flask_session import Session
from cachelib.file import FileSystemCache

app = Flask(__name__)

SESSION_TYPE = 'cachelib'
SESSION_SERIALIZATION_FORMAT = 'json'
SESSION_CACHELIB = FileSystemCache(threshold=500, cache_dir="/sessions")
app.config.from_object(__name__)
Session(app)

@app.route('/')
def home():
    session['history'] = []
    return render_template('index.html')

@app.route('/route1')
def route1():
    session['history'].append('route1')
    session.modified = True
    return {"history": session['history']}

@app.route('/route2')
def route2():
    def generate():
        full_response = ''
        for piece in text_generator():
            full_response += piece
            yield f"data: {piece}\n\n"
        
        session['history'].append(full_response)
        session.modified = True
    
    return Response(stream_with_context(generate()), mimetype='text/event-stream')

@app.route('/reset')
def reset():
    session['history'] = []
    session.modified = True
    return 'Reset complete.'

# In reality this returns different text each time, from AI
def text_generator():
    yield 'route2'

if __name__ == '__main__':
    app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask Session Test</title>
    <script>
        async function fetchRoute(route) {
            const response = await fetch(route);

            if (response.ok) {
                const data = await response.json();
                document.getElementById('response').textContent = JSON.stringify(data, null, 2) + '\n';
            }
        }

        function setupEventSource() {
            const eventSource = new EventSource('/route2');
            
            eventSource.onmessage = function(event) {
                document.getElementById('response').textContent += event.data + '\n';
            };

            eventSource.onerror = function(event) {
                console.error("EventSource failed:", event);
                eventSource.close();
            };

            eventSource.onopen = function() {
                console.log("Connection to /route2 opened.");
                document.getElementById('response').textContent += 'Streaming data from /route2...\n';
            };
        }

        async function resetSession() {
            const response = await fetch('/reset');
            const data = await response.text();
            document.getElementById('response').textContent = data;
        }
    </script>
</head>
<body>
    <h1>Flask Session Test</h1>
    <button onclick="fetchRoute('/route1')">Trigger Route 1</button>
    <button onclick="setupEventSource()">Trigger Route 2</button>
    <button onclick="resetSession()">Reset Session</button>
    <pre id="response"></pre>
</body>
</html>

Click Route1, then Route2, then Route1 again: I would expect (and require) the history to include "Route2", but it does not. This is the session extension I'm using: https://flask-session.readthedocs.io/en/latest/usage.html Thanks in advance for any advice.

Upvotes: 0

Views: 33

Answers (0)

Related Questions