tokens example python curl flask flask-session

python - example - token flask



La sesiĆ³n de matraz no se actualiza de forma consistente con las solicitudes paralelas (1)

Estoy notando que cuando las solicitudes que se ejecutan en paralelo modifican la session de Flask, solo se graban algunas claves. Esto sucede tanto con la sesión de cookies predeterminada de Flask como con Flask-Session utilizando el backend de Redis. El proyecto no es nuevo, pero esto solo se hizo notorio una vez que ocurrieron muchas solicitudes al mismo tiempo para la misma sesión.

import time from flask import Flask, session from flask_session import Session app = Flask(__name__) app.secret_key = "example" app.config["SESSION_TYPE"] = "redis" Session(app) @app.route("/set/<value>") def set_value(value): """Simulate long running task.""" time.sleep(1) session[value] = "done" return "ok/n" @app.route("/keys") def keys(): return str(session.keys()) + "/n"

El siguiente script de shell demuestra el problema. Observe que todas las solicitudes están completas, pero solo una clave está presente en el listado final, y es diferente entre las ejecuciones de prueba.

# set session curl -c ''cookie'' http://localhost:5007/keys # run parallel curl -b ''cookie'' http://localhost:5007/set/key1 && echo "done1" & curl -b ''cookie'' http://localhost:5007/set/key2 && echo "done2" & curl -b ''cookie'' http://localhost:5007/set/key3 && echo "done3" & wait # get result curl -b ''cookie'' http://localhost:5007/keys

$ sh test.sh dict_keys([''_permanent'']) ok ok ok done3 done1 done2 dict_keys([''_permanent'', ''key2'']) $ sh test.sh dict_keys([''_permanent'']) ok done3 ok ok done2 done1 dict_keys([''_permanent'', ''key1''])

¿Por qué no están todas las llaves presentes después de que terminen las solicitudes?


Las sesiones basadas en cookies no son seguras para subprocesos. Cualquier solicitud dada solo ve la cookie de sesión enviada con ella, y solo devuelve la cookie con las modificaciones de esa solicitud. Esto no es específico de Flask, es cómo funcionan las solicitudes HTTP.

Emite tres peticiones en paralelo. Todos leen la cookie inicial que solo contiene la clave _permanent , envían sus solicitudes y obtienen una respuesta que establece una cookie con su clave específica. Cada cookie de respuesta tendría la clave _permanent y la clave key_keyN solamente. Cualquiera que sea la solicitud finaliza la última escritura en el archivo, sobrescribiendo los datos anteriores, por lo que queda solo con su cookie.

En la práctica esto no es un problema. La sesión no está realmente destinada a almacenar datos que cambian rápidamente entre solicitudes, para eso es la base de datos. Las cosas que modifican la sesión, como iniciar sesión, no suceden en paralelo a la misma sesión (y son idempotentes de todos modos).

Si está realmente preocupado por esto, use una sesión del lado del servidor para almacenar los datos en una base de datos. Las bases de datos son buenas para sincronizar escrituras.

Ya está utilizando Flask-Session y Redis, pero al profundizar en la implementación de Flask-Session se revela por qué tiene este problema. Flask-Session no almacena cada clave de sesión por separado, escribe un único valor serializado con todas las claves. Por lo tanto, tiene el mismo problema que las sesiones basadas en cookies: solo lo que estuvo presente durante esa solicitud se vuelve a colocar en Redis, sobrescribiendo lo que sucedió en paralelo.

En este caso, será mejor escribir su propia subclase SessionInterface para almacenar cada clave individualmente. save_session para configurar todas las claves en session y eliminar las que no estén presentes.