Search code examples
neo4jneo4j-python-driver

Neo4j Python driver: How do you set a timeout for a query?


How do you limit the query execution to say 10 seconds?

The scenario I'm encountering is that I have a LOT of nodes in my graph and I want to see if a relationship exists between 2 nodes, if it takes longer than 10 seconds, the chances are that the relationship doesn't exist. But without a timeout, the query doesn't terminate!


Solution

  • It depends on the API you are using (different APIs serve different purposes).

    All snippets assume to be embedded in this code

    import neo4j  # version 5.27
    
    
    URL = "neo4j://neo4j.example.com:7687"
    AUTH = ("username", "password")
    DB = "neo4j"  # best practice to specify database where possible
    TIMEOUT = 10  # seconds
    
    
    with neo4j.GraphDatabase.driver(URL, auth=AUTH) as driver:
        ...  # <- the snippet goes here
    

    driver.execute_query

    This is the API recommended for most use-cases. It provides retries and manages sessions and transactions for you.

    driver.execute_query(
        neo4j.Query(
            "RETURN 1",
            timeout=TIMEOUT,
        ),
        database_=DB,
        routing_="r",  # if a read query
    )
    

    Managed Transaction

    This is equivalent to the above except that it

    • allows for more complex logic within the transaction
    • allows for multiple queries within the transaction
    • is potentially less optimized because the driver can make fewer assumptions about the nature of the transaction.
    @neo4j.unit_of_work(timeout=TIMEOUT)
    def work(tx: neo4j.ManagedTransaction):
        return list(tx.run("RETURN 1"))
    
    
    with driver.session(database=DB) as session:
        session.execute_read(work)
        # or session.execute_write(work) depending on the type of query
    

    session.run a.k.a. auto-commit transactions

    This API is primarily useful for queries that manage their own transactions server-side. E.g., CALL { …​ } IN TRANSACTIONS.

    with driver.session(
        database=DB,
        default_access_mode=neo4j.READ_ACCESS,  # if a read query
    ) as session:
        session.run(
            neo4j.Query(
                "RETURN 1",
                timeout=TIMEOUT,
            )
        )
    

    Unmanaged transactions

    This API is mostly for libraries wrapping the driver or for clients that need full control over transactions, e.g., because they want to roll their own retry logic.

    with driver.session(
        database=DB,
        default_access_mode=neo4j.READ_ACCESS,  # if a read query
    ) as session:
        with session.begin_transaction(timeout=TIMEOUT) as tx:
            list(tx.run("RETURN 1"))