Как сохранить уникальное соединение Rserve за сеанс?

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

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

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

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

flask.g.my_connection = pyRserve.connect()

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

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

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.

Другие вопросы по тегам