Search code examples
pythonneo4jdeadlock

How to avoid and handle Neo.TransientError.Transaction.DeadlockDetected?


When doing load testing, I am seeing Deadlock errors happening occasionally, I added retries and its been working well. However, how do I know how to improve? The errors are quite vague so I cannot tell which query is causing this

{code: Neo.TransientError.Transaction.DeadlockDetected} {message: ForsetiClient[transactionId=75637, clientId=2431] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=75634, clientId=2450]} on NODE_RELATIONSHIP_GROUP_DELETE(116) because holders of that lock are waiting for ForsetiClient[transactionId=75637, clientId=2431].

The weird thing is I dont think I have code that does a relationship delete. I am actually doing MERGE to add nodes and relationships along the lines of:

MERGE (o:Org {id: $orgId}) 
SET o.name=$name

MERGE (a:Item {id: $itemId})
SET a.orgId=$orgId,
    a.name=$itemName

MERGE (s:SubItem {id: $subItemId})
SET s.name=$subItemName

MERGE (o)-[:HAS_ITEM]->(a)
MERGE (a)-[:HAS_SUB_ITEM]->(s)

UPDATE:

Managed to identity the part causing the deadlock. I am modelling tags as a node and I suspect when many items use the same tag, and I try to merge the relationship, it causes a deadlock

MATCH (t:Tag {name: "a"})
MATCH (i:Item {name: "x"})
MERGE (i)-[:TAGGED]->(t)

I think this is the part causing deadlock often, how might I avoid this?


Solution

  • Found the reason why deadlocks happen very frequently already. Also thanks to @Tomaž Bratanič's whose link to the docs helped. Specifically this part

    Lock taken on a node during the transaction creation phase to prevent deletion of that node and/or relationship group. This is different from the NODE lock in order to allow concurrent label and property changes together with relationship modifications.

    And

    Table 2. Obtained locks for graph modifications Creating a relationship* If the node is sparse: NODE lock. If a node is dense: NODE DELETE prevention lock.

    Important part is the part about dense node. Because I am modelling :Category as a node, 1 category can have many edges creating a "dense node".

    Googling more about it, I found https://medium.com/neo4j/graph-modeling-all-about-super-nodes-d6ad7e11015b and started attempting to make the node less dense with some trade offs. Basically I made it a category specific to the "user" rather than globally. So instead of the category being uniqued by name, I also added a userId of sort so its a "composite key". I also added a TEXT index on name such that I can query easily for all category regardless of user quickly