Resource Reclamation Logic
Neo4j distinguishes between a graceful cancellation and a timeout primarily through the state of the Bolt connection. When a client explicitly closes a session or the driver sends a cancellation signal, the server attempts to interrupt the executing thread immediately. However, if the session is closed abruptly (e.g., a network drop or process crash), the server cannot distinguish this from a silent network lag until a connection failure is detected.
Likely Execution Behavior
In the event of an abrupt client-side closure, the server-side thread typically continues processing until one of three events occurs:
- I/O Attempt: The server attempts to stream a result back to the client, fails due to a broken pipe, and subsequently triggers a rollback.
- Heartbeat Failure: The Bolt protocol's keep-alive mechanism fails to receive a response, leading the server to terminate the connection and the associated transaction.
- Global Timeout: The
dbms.transaction.timeout limit is reached, forcing a server-side termination regardless of connection state.
Ensuring Immediate Release
To minimize the window where orphaned threads consume resources, you should implement a combination of driver-level and server-level constraints. There is no single "magic switch" to make the server instantly aware of a TCP drop without waiting for a timeout or I/O failure, but the following settings reduce the lag:
- Tighten Transaction Timeouts: Set
dbms.transaction.timeout to a value that reflects your maximum acceptable query duration to prevent "zombie" queries from running indefinitely.
- Configure TCP Keepalives: Adjust the OS-level TCP keepalive settings on the server to detect dead peers faster than the default (often 2 hours).
- Driver-side Timeouts: Use the driver's
withTimeout() or similar session configurations to ensure the client does not hang, though this does not guarantee immediate server-side cleanup.
Verification Steps
To verify how your specific version of Neo4j handles these closures, perform the following test:
# 1. Start a long-running query (e.g., a complex Cartesian product) via Cypher Shell
# 2. Force-kill the Cypher Shell process (kill -9)
# 3. Immediately run the following query in a separate session to check active transactions:
CALL dbms.listTransactions()
If the transaction remains in the list after the client is dead, the server is relying on the global timeout or heartbeat failure rather than immediate connection detection.
Missing Diagnostic: Are you using a load balancer or connection pooler (like HAProxy) between the client and the server? These intermediaries often mask abrupt client closures from the Neo4j engine, forcing the server to rely entirely on the dbms.transaction.timeout.