2

私は、neo4jボルトドライバーを使用してneo4jグラフdbと通信するdjangoで書かれたバックエンドを持っています。

シングルトンを使用して接続を処理し、接続が最初に確立された場所とは別の場所からアクセスするたびに、ボルトドライバーが接続を閉じます (たとえば、ビューで接続を開き、シグナルでアクセスし、ビューに保存すると、接続が失われます)。

私が思いついた主な問題を抽出して、以下の小さなコード例に分解しようとしました。

動作の説明、またはより良い解決策をいただければ幸いです;)

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、たとえば apost-save信号)。ただし、「GraphMapper」A から B への参照を渡すことはできません。したがって、上記で説明したシングルトン実装を思いつきました。シングルトンがすべての場所で (1 つの要求内で) まったく同じインスタンスであることを確認しました。しかし、メソッド呼び出しを介してコンテキスト (パッケージ、クラス、またはメソッド) を終了し、次の場所で「GraphMapper」インスタンスを取得すると、接続が閉じられます。「GraphMapper」への参照カウントとその接続も確認しましたが、ガベージコレクターはそれを削除しないでください。接続が閉じられていないと言うことはめったにありません。ただし、グラフに書き込むと、接続拒否エラーが発生します。

PS: 役に立たない不要なコードがあることはわかっています。これは説明のみを目的としており、ガベージ コレクターが一部のオブジェクトを強制終了しないようにしたかったのです。

4

0 に答える 0