Reputation: 41
I have a Spring, Hibernate, and Wicket application set up to read internationalized json content items from a database and pass them out via a request on an api url. The codebase responsible for passing out the data is a smaller part of an overall website structure developed for an enterprise client.
The api functions fine in over 90 percent of cases, but the client is experiencing an interesting occassional issue that might be stemming from orphaned hibernate sessions. The request will fail via the php script and give the error:
Warning: file_get_contents( http://client.net/api/attachment_lines?ce=false&language=en®ion=na&ts=1341592326) [function.file-get-contents]: failed to open stream: Redirection limit reached, aborting in client_api->send_request() (line 38 of <sitepath>/api.class.php).
And will spawn the following error in the tomcat server log:
09:15:00,200 ERROR [RequestCycle] failed to lazily initialize a collection of role: com.client.data.AttachmentLineCode.attachmentSublineCodes, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.client.data.AttachmentLineCode.attachmentSublineCodes, no session or session was closed
The application is configured within spring to use the OpenSessionInViewFilter and @Transactional annotation design pattern, so I'm not sure what's causing intermittent request failures. In addition to this, the client states that the api will continue to fail for about 15 minutes following the issue, which seems really wacky given the configuration. Within the web.xml, here is the declaration of the filter:
<filter>
<filter-name>openEntityManagerInView</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openEntityManagerInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Within code, here is the transactional annotation on the generic DAO which is extended by the Content Item DAO:
@Transactional(noRollbackFor={javax.persistence.EntityNotFoundException.class, org.springframework.orm.ObjectRetrievalFailureException.class})
public class GenericDaoHibernate<T, PK extends Serializable> implements GenericDao<T, PK> {
@Autowired
private SessionFactory sessionFactory;
Within the generic DAO as well, here is where I retrieve and use sessions:
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
protected Criteria createCacheableCriteria(Class<T> clazz) {
Criteria criteria = createNonCacheableCriteria(clazz);
criteria.setCacheable(true);
criteria.setCacheMode(CacheMode.NORMAL);
return criteria;
}
protected Criteria createCacheableCriteria(Class<?> clazz, String alias) {
Criteria criteria = createNonCacheableCriteria(clazz, alias);
criteria.setCacheable(true);
criteria.setCacheMode(CacheMode.NORMAL);
return criteria;
}
protected Criteria createNonCacheableCriteria(Class<?> clazz) {
Session session = getSession();
Criteria criteria = session.createCriteria(clazz);
criteria.setCacheable(false);
criteria.setCacheMode(CacheMode.IGNORE);
return criteria;
}
protected Criteria createNonCacheableCriteria(Class<?> clazz, String alias) {
Session session = getSession();
Criteria criteria = session.createCriteria(clazz, alias);
criteria.setCacheable(false);
criteria.setCacheMode(CacheMode.IGNORE);
return criteria;
}
Is there some sort of way that the session could get orphaned in this set up? Is there some sort of built in timeout to hibernate sessions that could be causing this issue? Possibly issues with caching? Thanks in advance for your help.
Upvotes: 3
Views: 1024
Reputation: 41
The solution here has nothing to do with Hibernate or Spring, and resides solely in my error not noting the differences between the production environment and our development/staging. The production environment implemented a complex load balancing strategy without sticky sessions.
It turns out that Wicket's Request/Response cycle involves caching a buffered response following a POST. The corresponding GET coming back to pick up that response would throw a 302 occasionally because the load balancing would forward the request to a server without the cached response, and the proxy objects would be lost in oblivion. The relevant piece of code I chose to implement to resolve this is placed within my Application.java under init():
public class ClientApplication extends SpringWebApplication {
...
public void init() {
...
getRequestCycleSettings().setRenderStrategy(IRequestCycleSettings.ONE_PASS_RENDER);
This changes Wicket's rendering strategy configuration to not buffer responses. An issue emerges as a result that allows the classic "refresh double submit" problem. As a result, this isn't necessarily an ideal solution, but the client didn't want to use sticky session enabled load balancing, and didn't mind having the double submit issue.
For more details on this issue, and a far more eloquent/structured answer, see: http://blog.comsysto.com/2011/04/08/lost-in-redirection-with-apache-wicket/
Upvotes: 1