0

I am persisting a Node entity that contains relationships to few other entities. This persist works fine when I am doing it one at a time, however if I run this concurrently, I get NPE at org.neo4j.ogm.mapper.EntityGraphMapper

java.lang.NullPointerException: null
at org.neo4j.ogm.mapper.EntityGraphMapper.updateRelationship(EntityGraphMapper.java:618) ~[neo4j-ogm-1.1.2.jar:na]
at org.neo4j.ogm.mapper.EntityGraphMapper.mapRelationshipEntity(EntityGraphMapper.java:481) ~[neo4j-ogm-1.1.2.jar:na]
at org.neo4j.ogm.mapper.EntityGraphMapper.link(EntityGraphMapper.java:330) ~[neo4j-ogm-1.1.2.jar:na]
at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntityReferences(EntityGraphMapper.java:265) ~[neo4j-ogm-1.1.2.jar:na]
at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntity(EntityGraphMapper.java:158) ~[neo4j-ogm-1.1.2.jar:na]

Here is my Node entity's crux:

@NodeEntity
public class Post {
   @Relationship(type = "POST_BY_USER", direction = Relationship.INCOMING)
   User poster;

   @Relationship(type = "POST_TO_STORE", direction = Relationship.OUTGOING)
   Store toStore;

   @Relationship(type = "POST_PRODUCT", direction = Relationship.INCOMING)
  Product product;

  @Relationship(type = "POST_INSPIRATION", direction = Relationship.INCOMING)
  Product_Inspiration productInspiration;
}

I tried persisting with both using a GraphRepository with (@Transactional)as well as using a session with the transaction, in both scenarios, i hit the same issue with concurrency.

Could someone please let me know how I could possibly fix this issue? Since I am getting this issue when I bombard concurrent requests, I am not sure if this could be something with the code flow as such.

As requested by Vince about code how to send concurrent requests, I am using axon cqrs framework with Play and I send multiple concurrent requests to my Play application's rest API which via axon invokes concurrent writes to Neo4j via postProduct method. here is how my write code looks like.

   def postProduct(productId: ProductId, product2Post: Product2Post):     Post = workNLogOnFail(
  doPost(productId, product2Post),
  "postProduct"
  )

  private def doPost(productId: ProductId, product2Post: Product2Post): Post = {
  val product: Product = configureDomainEntity(productId, product2Post)
  val storeId: StoreId = storeService1.findOrCreateStore(product2Post.host)
  val post: Post = commonService.configurePost(product2Post.commonData2Post.relationInfo, isProduct = true) { (x: Post) =>
  x.setToStore(storeService1.updateStoreForProductPost(x, storeId))
  x.setProduct(product)
}
val persistedPost = xtPostProduct(product, post)
commonService.addUrlMapping(product2Post.commonData2Post, productId.identifier)
persistedPost
}
private def xtPostProduct(product: Product, post: Post): Post = {
Try {
  val tx: Transaction = session.beginTransaction()
  logger.debug(s"saving product")
  //      session.save(product)
  logger.debug(s"updating user")
  //      session.save(post.getPoster)
  logger.debug(s"posting product")
  session.save(post)
  tx.commit()
  post
  }.get
  }

i tried @Transanctional with GraphRepository as well as session in the method xtPostProduct.

Gaurav Abbi
  • 645
  • 9
  • 23
  • Please could you post some code here showing how you're doing the concurrent writes? – Vince Sep 16 '15 at 21:26
  • Thanks for the code Gaurav. I am not at all familiar with axon, but the test harness for the OGM contains a number of concurrency tests. That's not to say we don't have concurrency bugs - but we haven't found them yet. Please could you confirm that the method `doPost` is not sharing state somehow between threads and tripping over itself. In particular are the methods on `StoreService` and `CommonService` as well as `configureDomainEntity` thread safe? – Vince Sep 17 '15 at 09:32

1 Answers1

0

Figured it out. The issue was that due to spring DI wiring, my session or also the one used by repositories was not per unit of work. Since i am invoking Database operations via Axon, having the normal way of using a Session Bean with the scope of "session" will not work. I have reverted to manually creating session for each Axon-event that I need to handle. Since essentially for me, that is my unit of work !!.

Gaurav Abbi
  • 645
  • 9
  • 23