У меня есть бэкэнд, написанный на 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 .: Я знаю, что есть некоторый бесполезный и ненужный код, он только для иллюстрации, и я хотел убедиться, что сборщик мусора не убил некоторые объекты.