Как подключиться к Cassandra внутри приложения Pylons?

Я создал новый проект Pylons и хотел бы использовать Cassandra в качестве моего сервера базы данных. Я планирую использовать Pycassa для использования cassandra 0.7beta. К сожалению, я не знаю, где создать экземпляр соединения, чтобы он был доступен в моем приложении.

Цель состоит в том, чтобы:

  • Создайте пул при запуске приложения
  • Получить соединение из пула для каждого запроса и сделать его доступным для моих контроллеров и библиотек (в контексте запроса). Лучше всего было бы получить связь из пула "лениво", т.е. Только при необходимости
  • Если связь была использована, отпустите ее, когда запрос обработан.

Кроме того, есть ли что-то важное, что я должен знать об этом? Когда я вижу некоторые комментарии, такие как "Будьте осторожны при использовании QueuePool с use_threadlocal = True, особенно с включенными попытками. Возможно, потребуется синхронизация, чтобы предотвратить изменение соединения, пока другой поток использует его". Что это значит?

Спасибо.

- Pierre

Ответ 1

Ну. Я работал немного больше. Фактически, использование диспетчера соединений, вероятно, не очень хорошая идея, так как это должен быть контекст шаблона. Кроме того, открытие соединения для каждого потока не является большой проблемой. Открытие соединения для каждого запроса будет.

Я закончил с pycassa.connect_thread_local() в app_globals, и там я иду.

Ответ 2

Хорошо. Я немного поработал, я многому научился, и я нашел возможный ответ.

Создание пула

Лучшее место для создания пула, по-видимому, находится в файле app_globals.py, который в основном представляет собой контейнер для объектов, которые будут доступны "на протяжении всего срока действия приложения". Точно, что я хочу для пула, на самом деле.

Я только что добавил в конец файла свой код инициализации, который принимает настройки из файла конфигурации pylons:

"""Creating an instance of the Pycassa Pool"""
kwargs = {}

# Parsing servers
if 'cassandra.servers' in config['app_conf']:
    servers = config['app_conf']['cassandra.servers'].split(',')
    if len(servers):
        kwargs['server_list'] = servers

# Parsing timeout
if 'cassandra.timeout' in config['app_conf']:
    try:
        kwargs['timeout'] = float(config['app_conf']['cassandra.timeout'])
    except:
        pass

# Finally creating the pool
self.cass_pool = pycassa.QueuePool(keyspace='Keyspace1', **kwargs)

Я мог бы сделать лучше, например, переместить это в функции или поддерживать дополнительные параметры (размер пула,...). Что я буду делать.

Получение соединения при каждом запросе

Ну. Кажется, это простой способ: в файле base.py добавить что-то вроде c.conn = g.cass_pool.get() перед вызовом WSGIController, что-то вроде c.conn.return_to_pool() после. Это просто и работает. Но это получает соединение из пула, даже если это не требуется контроллером. Я должен копать немного глубже.

Создание диспетчера соединений

У меня возникла простая идея создать класс, который будет создан при каждом запросе в файле base.py и который автоматически получит соединение из пула по запросу (и отпустите его после). Это действительно простой класс:

class LocalManager:
    '''Requests a connection from a Pycassa Pool when needed, and releases it at the end of the object life'''

    def __init__(self, pool):
        '''Class constructor'''
        assert isinstance(pool, Pool)
        self._pool = pool
        self._conn = None

    def get(self):
        '''Grabs a connection from the pool if not already done, and returns it'''
        if self._conn is None:
            self._conn = self._pool.get()
        return self._conn

    def __getattr__(self, key):
        '''It cooler to write "c.conn" than "c.get()" in the code, isn't it?'''
        if key == 'conn':
            return self.get()
        else:
            return self.__dict__[key]

    def __del__(self):
        '''Releases the connection, if needed'''
        if not self._conn is None:
            self._conn.return_to_pool()

Просто добавлено c.cass = CassandraLocalManager(g.cass_pool) перед вызовом WSGIController в base.py, del(c.cass) после, и я все закончил.

И он работает:

conn = c.cass.conn
cf = pycassa.ColumnFamily(conn, 'TestCF')
print cf.get('foo')

\ о /

Я не знаю, лучший ли это для этого. Если нет, сообщите мне =) Кроме того, я до сих пор не понял часть "синхронизации" в исходном коде Pycassa. Если это необходимо в моем случае и что мне делать, чтобы избежать проблем.

Спасибо.