Using SDN 3.3.1 and Neo4j 2.1.7 in external server setup.
I am having java.net.SocketTimeoutException: Read timed out
whenever I do the following execution pattern :
- Retrieve an entity :
MyEntity entity = myRepository.findByUuid(uuid);
- Delete a relationship of that entity :
neo4jOperations.query("match (e{uuid:"theuuid"})<-[r:THE_RELATION]-() delete r);
- Change a property of the entity :
entity.setTitle("New title");
- Save the entity :
myRepository.save(entity);
--> waiting a long time then got theSocketTimeoutException
After some analysis, it appears to me that 1. does http calls inside AND outside the transaction as you can see in this Neo4j http log extract :
127.0.0.1 - - [20/août/2015:10:47:57 +0200] "POST /db/data/transaction HTTP/1.1" 201 659 "-" "neo4j-rest-graphdb/0"
127.0.0.1 - - [20/août/2015:10:47:57 +0200] "GET /db/data/node/135/relationships/in/WITH_ROLE HTTP/1.1" 200 391 "-" "neo4j-rest-graphdb/0"
127.0.0.1 - - [20/août/2015:10:47:57 +0200] "GET /db/data/node/149 HTTP/1.1" 200 1780 "-" "neo4j-rest-graphdb/0"
127.0.0.1 - - [20/août/2015:10:47:57 +0200] "GET /db/data/node/135/relationships/out/DEFAULT_ENTITY HTTP/1.1" 200 401 "-" "neo4j-rest-graphdb/0"
127.0.0.1 - - [20/août/2015:10:47:57 +0200] "GET /db/data/node/227 HTTP/1.1" 200 1884 "-" "neo4j-rest-graphdb/0"
127.0.0.1 - - [20/août/2015:10:47:57 +0200] "GET /db/data/node/135/relationships/in/WITH_PENDING_ROLE HTTP/1.1" 200 2 "-" "neo4j-rest-graphdb/0"
So my first question would be :
- Why an operation like fetching a entity generates queries that uses the transaction endpoints and others that do not ?
Then, the delete operation in 2. is correctly done inside the transaction :
127.0.0.1 - - [20/août/2015:10:47:58 +0200] "POST /db/data/transaction/2720 HTTP/1.1" 200 254 "-" "neo4j-rest-graphdb/0"
The point 3. obviously generates no http request.
And at the end, the point 4. which generate a SocketTimeoutException
after being "blocked" for a time (30 sec to be precise), finally generate 2 http requests :
127.0.0.1 - - [20/août/2015:10:48:28 +0200] "DELETE /db/data/transaction/2720 HTTP/1.1" 200 26 "-" "neo4j-rest-graphdb/0"
127.0.0.1 - - [20/août/2015:10:48:28 +0200] "PUT /db/data/node/135/properties HTTP/1.1" 204 0 "-" "neo4j-rest-graphdb/0"
The delete is because the transaction is rollbacked, and I think the PUT corresponds to the save()
In my opinion, a deadlock is happening because of the PUT being outside of the transaction ! So, the main question is :
- Why is the
save()
making a PUT outside of the transaction and not a POST inside the transaction ? Is there a way to force the entity update to be done using the transactional endpoint ?
Thanks :)
EDIT : Added SDN config
<beans ...>
<tx:annotation-driven />
<context:component-scan base-package="com.myproject.mw.neo4j.service,com.myproject.mw.neo4j.aspect" />
<aop:aspectj-autoproxy />
<!-- External database config -->
<bean id="graphDatabaseServiceExternal" class="org.springframework.data.neo4j.rest.SpringCypherRestGraphDatabase"
lazy-init="true">
<constructor-arg index="0" value="${neo4j.path}" />
</bean>
<alias name="graphDatabaseService${neo4j.mode}" alias="graphDatabaseService" />
<neo4j:config base-package="com.myproject.mw.neo4j.domain"
graphDatabaseService="graphDatabaseService" />
<neo4j:repositories base-package="com.myproject.mw.neo4j.repository" />
</beans>
EDIT 2 : Added entities definition and simple test to reproduce
Note that my Neo4j server is on localhost.
The test :
@Test
@Transactional
@Rollback(false)
public void testEntityNotFound() {
BusinessCard card = genericRepository.findByUuid("4bce6162-bc6f-bce2-bc71-bc70b63dff00");
Entity entity = genericRepository.findByUuid("04947df8-0e9e-4471-a2f9-9af509fb5889");
neo4jOperations.createRelationshipBetween(neo4jOperations.getNode(entity.getId()),
neo4jOperations.getNode(card.getId()), "FAKE2", null);
neo4jOperations.save(card);
}
BusinessCard entity :
public class BusinessCard extends GenericNode {
@Indexed
private String title;
@RelatedTo(type = RelationNames.WITH_ROLE, direction = Direction.INCOMING)
private User user;
@RelatedTo(type = RelationNames.WITH_PENDING_ROLE, direction = Direction.INCOMING)
private User pendingUser;
@RelatedTo(type = RelationNames.DEFAULT_ENTITY)
private Entity defaultEntity;
}
And the Entity entity :
public class Entity extends GenericNode {
private String logo;
@Indexed
private String entityName;
@RelatedTo(type = RelationNames.IS_IN_CITY)
private CityNode mainCity;
@RelatedTo(type = RelationNames.IS_IN_COUNTRY)
private CountryNode mainCountry;
@RelatedTo(type = RelationNames.IS_IN_COUNTRIES)
private Set<CountryNode> countries;
@Fetch
@RelatedToVia(type = RelationNames.TRANSLATION)
private Set<EntityToEntityTranslatedContent> entityTranslatedContent;
@Fetch
@RelatedTo(type = RelationNames.HAS_KEY_STAGES)
private KeyStage lastKeyStage;
@GraphProperty(propertyType = Long.class)
private Date lastProfileUpdateDateTime;
private Integer profilCompletionIndice;
@RelatedToVia(type = RelationNames.WORKS_AT, direction = Direction.INCOMING)
private Set<BusinessCardWorkAt> employees = new HashSet<>();
...+34 more fields...
}