Храните большие данные или подключение к службе за сеанс Flask

Я пишу небольшое приложение Flask и подключаю его к Rserve с помощью pyRserve. Я хочу, чтобы каждый сеанс начинался, а затем поддерживал собственное соединение Rserve.

Что-то вроде этого:

session['my_connection'] = pyRserve.connect()

не работает, потому что объект подключения не поддерживает сериализацию JSON. С другой стороны, примерно так:

flask.g.my_connection = pyRserve.connect()

не работает, потому что не сохраняется между запросами. Чтобы усугубить сложность, похоже, что pyRserve не предоставляет какой-либо идентификатор для соединения, поэтому я не могу сохранить идентификатор соединения в сеансе и использовать его для получения правильного соединения перед каждым запросом.

Есть ли способ создать уникальное соединение для каждого сеанса?


person izyda    schedule 10.02.2015    source источник
comment
Почему вам нужно использовать одно и то же соединение для сеанса?   -  person dirn    schedule 10.02.2015
comment
Потому что мне нужно, чтобы объекты в пространстве имен R сохранялись для одного и того же пользователя во время сеанса (но не были видимыми / доступными для других пользователей). Например, пользователь может загрузить некоторые данные и подобрать модель - я хочу иметь доступ к этой модели (без ее переоборудования) на других страницах (то есть после того, как были сделаны другие запросы Flask).   -  person izyda    schedule 10.02.2015
comment
Понятно. Я не уверен, что мне действительно нужно повторно используемое соединение для каждого пользователя. Мое единственное требование - чтобы пользовательское соединение / сеанс R имел возможность доступа к объектам R, созданным с использованием предыдущих запросов этого пользователя. Я полагаю, что работоспособное решение могло бы заключаться в том, чтобы соединение R сохраняло текущую рабочую область R на сервере, сохраняло идентификатор этой рабочей области в виде файла cookie и при новом запросе, чтобы новые соединения R считали это рабочее пространство обратно ...   -  person izyda    schedule 10.02.2015
comment
Взгляните на DeployR (deployr.revolutionanalytics.com) - он добавляет API и дополнительные функции поверх Rserve это упрощает управление этим типом требований.   -  person Andrie    schedule 10.02.2015
comment
@Andrie Я подумал об этом - хотя похоже, что есть только клиентские библиотеки для Java, Javascript и .NET. Я ограничен питоном ...   -  person izyda    schedule 10.02.2015
comment
Вы можете вызвать API напрямую, без использования клиентских библиотек. См. deployr.revolutionanalytics.com/documents//dev/api -doc / guide / или задайте вопрос на странице groups.google.com/ forum / #! forum / deployr   -  person Andrie    schedule 10.02.2015


Ответы (1)


Следующее применимо к любым глобальным данным Python, которые вы не хотите воссоздавать для каждого запроса, а не только к rserve, и не только к данным, уникальным для каждого пользователя.

Нам нужно какое-то общее место для создания соединения rserve для каждого пользователя. Самый простой способ сделать это - запустить multiprocessing.Manager как отдельный процесс. .

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()

Запустите его перед запуском вашего приложения, чтобы менеджер был доступен:

python rserve_manager.py

Мы можем получить доступ к этому менеджеру из приложения во время запросов, используя простую функцию. Предполагается, что у вас есть значение для user_id в сеансе (что, например, делает Flask-Login). В результате соединение rserve становится уникальным для каждого пользователя, а не для сеанса.

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

Доступ к нему внутри представления:

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

Это должно помочь вам начать работу, хотя есть много вещей, которые можно улучшить, например, не жестко кодировать адрес и пароль и не отбрасывать соединения с менеджером. Это было написано на Python 3, но должно работать с Python 2.

person davidism    schedule 10.02.2015