Драйвер болта Python neo4j теряет связь после переключения контекста - PullRequest
0 голосов
/ 07 ноября 2018

У меня есть бэкэнд, написанный на django, который использует болт-драйвер neo4j для связи с графиком neo4j.

Я использую Singleton для обработки соединения, и драйвер затвора закрывает соединение всякий раз, когда я получаю к нему доступ из другого места, отличного от того, где соединение было первоначально установлено (например, я открываю соединение в виде, получаю к нему доступ в сигнале и когда Я пытаюсь сохранить в представлении связь потеряна).

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

Буду признателен за любое объяснение поведения или даже лучшее решение;)

from neo4j.v1 import Driver, GraphDatabase, basic_auth, Session, Transaction


def main():
    gm = GraphMapper()
    gm.begin_atomic_transaction()

    print(f"graph connection closed before method? {gm.is_connection_closed()}") # -> false

    fill_transaction() #the context switch

    print(f"graph connection closed after method? {gm.is_connection_closed()}") # -> true

    if not gm.is_connection_closed():
        print(f"graph connection open - try to commit") # -> is never called
        gm.commit_atomic_transaction_and_close_session()


def fill_transaction():
    gm = GraphMapper()

    print(f"graph connection closed in method? {gm.is_connection_closed()}") # -> true

    gm.create_update_node("TestNode")


class GraphMapper:
    __instance = None
    __transaction = None  # type: Transaction
    __session = None  # type: Session
    __connection = None # type: Connection
    __driver = None  # type: Driver

    def __new__(cls, *args, **kwargs):
        if not isinstance(cls.__instance, cls):
            cls.__instance = object.__new__(cls, *args, **kwargs)
        return cls.__instance

    def __init__(self):
        self.__driver = GraphDatabase.driver("bolt://localhost:7687", auth=basic_auth("neo4j", "password"))

    def is_connection_closed(self):
        return self.__transaction.session._connection._closed

    def begin_atomic_transaction(self):
        self.__session = self.__driver.session()
        self.__transaction = self.__session.begin_transaction()
        self.__connection = self.__transaction.session._connection
        return self.__transaction

    def commit_atomic_transaction_and_close_session(self):
        result = self.__transaction.commit()

        self.__transaction = None
        return result

    def create_update_node(self, label):
        # Add Cypher statement to transaction

Детали реализации: у меня есть объект-оболочка "GraphMapper", который инкапсулирует соединение, сеанс и транзакцию драйвера. и разработан как единый экземпляр. Транзакция установлена ​​в точке (A, например, представление), но я не могу завершить транзакцию здесь. Мне нужно добавить дополнительные значения из местоположения (B, например, сигнал post-save). Однако я не могу передать ссылку на «GraphMapper» от A до B. Таким образом, я придумал реализацию синглтона, как объяснено выше. Я обеспечил, чтобы синглтон был точно таким же экземпляром во всех местах (в пределах одного запроса). Но в данный момент я выхожу из контекста (пакета, класса или метода) с помощью вызова метода и извлекаю экземпляр «GraphMapper» в самом следующем месте, соединение закрывается. Я даже проверил счетчик ссылок на «GraphMapper» и его соединение, и сборщик мусора не должен его удалять. Редко это говорит, что связь не закрыта. Но запись в график приводит к ошибке соединения отказано.

P.S .: Я знаю, что есть некоторый бесполезный и ненужный код, он только для иллюстрации, и я хотел убедиться, что сборщик мусора не убил некоторые объекты.

...