Store Large Data or a Service Connection Per Flask Session

Store large data or a service connection per Flask session

The following applies to any global Python data that you don't want to recreate for each request, not just rserve, and not just data that is unique to each user.

We need some common location to create an rserve connection for each user. The simplest way to do this is to run a multiprocessing.Manager as a separate process.

import atexit
from multiprocessing import Lock
from multiprocessing.managers import BaseManager
import pyRserve

connections = {}
lock = Lock()


def get_connection(user_id):
with lock:
if user_id not in connections:
connections[user_id] = pyRserve.connect()

return connections[user_id]


@atexit.register
def close_connections():
for connection in connections.values():
connection.close()


manager = BaseManager(('', 37844), b'password')
manager.register('get_connection', get_connection)
server = manager.get_server()
server.serve_forever()

Run it before starting your application, so that the manager will be available:

python rserve_manager.py

We can access this manager from the app during requests using a simple function. This assumes you've got a value for "user_id" in the session (which is what Flask-Login would do, for example). This ends up making the rserve connection unique per user, not per session.

from multiprocessing.managers import BaseManager
from flask import g, session

def get_rserve():
if not hasattr(g, 'rserve'):
manager = BaseManager(('', 37844), b'password')
manager.register('get_connection')
manager.connect()
g.rserve = manager.get_connection(session['user_id'])

return g.rserve

Access it inside a view:

result = get_rserve().eval('3 + 5')

This should get you started, although there's plenty that can be improved, such as not hard-coding the address and password, and not throwing away the connections to the manager. This was written with Python 3, but should work with Python 2.

In Python Flask: What are appropriate places to store data?

In order to store data for the lifetime of a single request, how should that be done?

The g object is designed for this. The documentation states:

Flask provides you with a special object that ensures it is only valid for the active request and that will return different values for each request.

Although the documentation refers to g as "global", that's not really accurate - "thread-global" would be better.

In order to store data for the lifetime of an application, how should that be done?

I think the answer to this question answers this as well (or better) than I could:
Preserving global state in a flask application

Flask could be used in a multi-process environment. Is it correct to assume that in such a mode of operation there will be multiple application-wide objects? (This would imply that all of these app or g objects then need to be initialized individually for the lifetime of each worker process.)

In a multi-process environment, each request is handled as a seperate thread, and g is intialized and destroyed on a per-request basis, so there will be as many concurrent g object as threads - though each thread can only see it's own. In most scenarios I suspect there should only ever one app object, an instance of the Flask() class created by the programmer, i.e. app = Flask(__name__) or similar.

Blueprints and Application Dispatching are two way of having "multiple" application objects, in as far as you have multiple applications running concurrently.

Initiate a deep learning model on application level in Flask

You are on the right track and the methods you listed are valid - depending on usecase one might be better than the other. As a concept you need to use the Singleton pattern.

Singleton Pattern will ensure that at any given point only one instance of the class/function exits hence keeping your memory consumption in check. For doing so you will need to ensure that the function is stateless, i.e. given a set of input parameters, it should give the output without altering the output for a different request.

There are many threads on singleton in Flask, I won't repeat it here. Here's a starting point
How to create a singleton object in Flask micro framework

Best practice to maintain a persistent variable in a Flask app

If you know your app will only run in one process with multiple threads (which is probably not the case in most production WSGI servers), one approach is to pair the resource with a threading.Lock, encapsulating both in a class. Then 'pass' a (single) instance of that class to the app via the config. Within the encapsulating class, guard access to the resource.

The Flask side might do

@app.route('/something')
def something():
app.config['RESOURCE'].action(...)
...

which calls a method that locks access to the resource and delegates the call.

def action(self, ...):
with self.lock:
self.resource.action(...)

Locking in this way will block other Flask threads that might want simultaneous access to resource.

There's a working example you can crib from here. Look at control.py, and ignore the part about running Flask in a separate thread.

This works fine in the dev server. All bets are off if you deploy under uwsgi/gunicorn.



Related Topics



Leave a reply



Submit