Reputation: 420
I have the problem that I need to run multiple task in parallel.
For this purpose I am using Futures.
One of this tasks is a simple select on a postgres database via hibernate, the problem is that every time this task gets executed a new postgres connection get created an soon postgres does not accept any more connections.
The application runs on a tomcat-server and uses connection pooling.
If i execute the task not in a different thread it works fine.
This is the method that uses hibernate:
@Override
public Future<MonitoringResult> performMonitoringAction() {
return getExecutorService().submit(() -> {
long milliseconds = System.currentTimeMillis();
Session session = null;
Transaction tx = null;
try {
session = HibernateUtil.getCurrentInstance().newSession();
tx = session.beginTransaction();
List<Entity> sle = (List<Entity>) session.createQuery("from Entity").list();
return new MonitoringResult(System.currentTimeMillis() - milliseconds, true);
} catch (Exception e) {
return new ExceptionMonitoringResult(System.currentTimeMillis() - milliseconds, e);
} finally {
if (tx != null) {
tx.commit();
}
if (session != null) {
session.close();
}
}
});
}
This is how it gets called:
public Response all() {
List<Future<MonitoringResult>> runningMonitorTasks = new ArrayList<>(monitoredServices.length);
// start all monitoring services
for (MonitorableService monitoredService : monitoredServices) {
runningMonitorTasks.add(monitoredService.performMonitoringAction());
}
HashMap<String, MonitoringResult> resultMap = new HashMap();
// collect results of monitoring services
for (int i = 0; i < monitoredServices.length; i++) {
MonitorableService monitoredService = monitoredServices[i];
Future<MonitoringResult> runningTask = runningMonitorTasks.get(i);
MonitoringResult result;
try {
result = runningTask.get(60, TimeUnit.SECONDS); // wait till task is finished
} catch (TimeoutException | InterruptedException | ExecutionException ex) {
LOGGER.log(Level.SEVERE, "Monitoring task failed", ex);
result = new ExceptionMonitoringResult(-1, ex);
}
logIfUnreachable(result, monitoredService);
resultMap.put(monitoredService.getServiceName(), result);
}
return Response.ok(resultMap).build();
}
Called this way it works fine:
public Response all() {
HashMap<String, MonitoringResult> resultMap = new HashMap();
// execute monitoring services
for (MonitorableService monitoredService : monitoredServices) {
Future<MonitoringResult> result = monitoredService.performMonitoringAction();
MonitoringResult get;
try {
get = result.get();
logIfUnreachable(get, monitoredService);
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(RestMonitorService.class.getName()).log(Level.SEVERE, null, ex);
get = new ExceptionMonitoringResult(-1, ex);
}
resultMap.put(monitoredService.getServiceName(), get);
}
return Response.ok(resultMap).build();
}
HibernateUtil class:
public class HibernateUtil implements ServletContextListener {
private static HibernateUtil currentInstance;
private SessionFactory sessionFactory;
private ServletContext servletContext;
private final Log logger = LogFactory.getLog(LoginInfo.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
// set current instance
currentInstance = this;
Configuration cfg = new Configuration().configure();
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(
cfg.getProperties());
sessionFactory = cfg.buildSessionFactory(builder.build());
servletContext = sce.getServletContext();
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// close session factory
if(sessionFactory!=null){
sessionFactory.close();
}
sessionFactory = null;
}
public static HibernateUtil getCurrentInstance() {
return currentInstance;
}
public Session newSession() {
return sessionFactory.openSession();
}
}
Upvotes: 0
Views: 216
Reputation: 420
The answers is real answer is that the problem occurred in a different place than I expected. But I going to share my solution as well.
Another service (not the one from my question) used the hibernate to. I a normal call in the of the web-application there is a listener that opens the connections before and on that closes the connections. But because the service got now executed on a different thread the connection was opened but never closed because the listeners did not get called.
Upvotes: 0
Reputation: 21
Can not comment yet, may worth check the source of HibernateUtil.getCurrentInstance()
to see what it is doing, it may use some threadlocal or create a new pool of connections. normally when connection got exhausted, likely due to creating a new pool instead of use existing pool to get connection.
Upvotes: 1