I have a problem regarding Hibernate and lazy loading.
Background:
I have a Spring MVC web app, I use Hibernate for my persistence layer. I'm using OpenSessionInViewFilter to enable me to lazy load entities in my view layer. And I'm extending the HibernateDaoSupport classes and using HibernateTemplate to save/load objects. Everything has been working quite well. Up until now.
The Problem:
I have a task which can be started via a web request. When the request is routed to a controller, the controller will create a new Runnable for this task and start the thread to run the task. So the original thread will return and the Hibernate session which was put in ThreadLocal (by OpenSessionInViewFilter) is not available to the new thread for the Task. So when the task does some database stuff I get the infamous LazyInitializationException.
Can any one suggest the best way I can make a Hibernate session available to the Task?
Thanks for reading.
Make your Runnable a Spring bean and add #Transactional annotation over run. You must be warned thou that this asynchronous task won't run in the same transaction as your web request.
And please don't start new thread, use pooling/executor.
Here is a working example on how to use the Hibernate session inside a Runnable:
#Service
#Transactional
public class ScheduleService {
#Autowired
private SessionFactory sessionFactory;
#Autowired
private ThreadPoolTaskScheduler scheduler;
public void doSomething() {
ScheduledFuture sf = scheduler.schedule(new Runnable() {
#Override
public void run() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(scheduler);
final Session session = sessionFactory.openSession();
// Now you can use the session
}
}, new CronTrigger("25 8 * * * *"));
}
}
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext() takes a reference to any Spring managed bean, so the scheduler itself is fine. Any other Spring managed bean would work as well.
Do I understand correctly, you want to perform some action in a completely dedicated background thread, right? In that case, I recommend you not accessing the Hibernates OpenSessionInViewFilter and further session logic for that thread at all, because it will, is you correctly noted, run in a decoupled thread and therefore information loaded in the original thread (i.e, the one that dealt with the initial HttpRequest). I think it would be wise to open and close the session yourself within that thread.
Otherwise, you might question why you are running that operation in a separated thread. May be it is sufficient to run the operation normally and present the user with some 'loading' screen in the meantime?
Related
I have a quarkus application with an async endpoint that creates an entity with default properties, starts a new thread within the request method and executes a long running job and then returns the entity as a response for the client to track.
#POST
#Transactional
public Response startJob(#NonNull JsonObject request) {
// create my entity
JobsRecord job = new JobsRecord();
// set default properties
job.setName(request.getString("name"));
// make persistent
jobsRepository.persist(job);
// start the long running job on a different thread
Executor.execute(() -> longRunning(job));
return Response.accepted().entity(job).build();
}
Additionally, the long running job will make updates to the entity as it runs and so it must also be transactional. However, the database entity just doesn't get updated.
These are the issues I am facing:
I get the following warnings:
ARJUNA012094: Commit of action id 0:ffffc0a80065:f2db:5ef4e1c7:0 invoked while multiple threads active within it.
ARJUNA012107: CheckedAction::check - atomic action 0:ffffc0a80065:f2db:5ef4e1c7:0 commiting with 2 threads active!
Seems like something that should be avoided.
I tried using #Transaction(value = TxType.REQUIRES_NEW) to no avail.
I tried using the API Approach instead of the #Transactional approach on longRunning as mentioned in the guide as follows:
#Inject UserTransaction transaction;
.
.
.
try {
transaction.begin();
jobsRecord.setStatus("Complete");
jobsRecord.setCompletedOn(new Timestamp(System.currentTimeMillis()));
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
}
but then I get the errors: ARJUNA016051: thread is already associated with a transaction! and ARJUNA016079: Transaction rollback status is:ActionStatus.COMMITTED
I tried both the declarative and API based methods again this time with context propagation enabled. But still no luck.
Finally, based on the third approach, I thought keeping the #Transactional on the Http request handler and leaving longRunning as is without declarative or API based transaction approaches would work. However the database still does not get updated.
Clearly I am misunderstanding how JTA and context propagation works (among other things).
Is there a way (or even a design pattern) that allows me to update database entities asynchronously in a quarkus web application? Also why wouldn't any of the approaches I took have any effect?
Using quarkus 1.4.1.Final with ext: [agroal, cdi, flyway, hibernate-orm, hibernate-orm-panache, hibernate-validator, kubernetes-client, mutiny, narayana-jta, rest-client, resteasy, resteasy-jackson, resteasy-mutiny, smallrye-context-propagation, smallrye-health, smallrye-openapi, swagger-ui]
You should return an async type from your JAX-RS resource method, the transaction context will then be available when the async stage executes. There is some relevant documentation in the quarkus guide on context propagation.
I would start by looking at the one of the reactive examples such as the getting started quickstart. Try annotating each resource endpoint with #Transactional and the async code will run with a transaction context.
I would like to know if it's ok to use Timer inside application scoped beans.
Example, lets say that I want to create a timer task that sends out a bunch of emails to every registered member one time per day. I'm trying to use as much JSF as possible and I would like to know if this is acceptable (it sounders a bit weird, I know).
Until now I have used all of the above inside a ServletContextListener. (I don't want to use any application server or cron job and I want to keep
the above things inside my web app.)
Is there a smart JSF way of doing this or should I stick with the old pattern?
Introduction
As to spawning a thread from inside a JSF managed bean, it would only make sense if you want to be able to reference it in your views by #{managedBeanName} or in other managed beans by #ManagedProperty("#{managedBeanName}"). You should only make sure that you implement #PreDestroy to ensure that all those threads are shut down whenever the webapp is about to shutdown, like as you would do in contextDestroyed() method of ServletContextListener (yes, you did?). See also Is it safe to start a new thread in a JSF managed bean?
Never use java.util.Timer in Java EE
As to using java.util.Timer in a JSF managed bean, you should absolutely not use the old fashioned Timer, but the modern ScheduledExecutorService. The Timer has the following major problems which makes it unsuitable for use in a long running Java EE web application (quoted from Java Concurrency in Practice):
Timer is sensitive to changes in the system clock, ScheduledExecutorService isn't.
Timer has only one execution thread, so long-running task can delay other tasks. ScheduledExecutorService can be configured with any number of threads.
Any runtime exceptions thrown in a TimerTask kill that one thread, thus making Timer dead, i.e. scheduled tasks will not run anymore. ScheduledThreadExecutor not only catches runtime exceptions, but it lets you handle them if you want. Task which threw exception will be canceled, but other tasks will continue to run.
Apart from the book quotes, I can think of more disadvantages:
If you forget to explicitly cancel() the Timer, then it keeps running after undeployment. So after a redeploy a new thread is created, doing the same job again. Etcetera. It has become a "fire and forget" by now and you can't programmatically cancel it anymore. You'd basically need to shutdown and restart the whole server to clear out previous threads.
If the Timer thread is not marked as daemon thread, then it will block the webapp's undeployment and server's shutdown. You'd basically need to hard kill the server. The major disadvantage is that the webapp won't be able to perform graceful cleanup via e.g. contextDestroyed() and #PreDestroy methods.
EJB available? Use #Schedule
If you target Java EE 6 or newer (e.g. JBoss AS, GlassFish, TomEE, etc and thus not a barebones JSP/Servlet container such as Tomcat), then use a #Singleton EJB with a #Schedule method instead. This way the container will worry itself about pooling and destroying threads via ScheduledExecutorService. All you need is then the following EJB:
#Singleton
public class BackgroundJobManager {
#Schedule(hour="0", minute="0", second="0", persistent=false)
public void someDailyJob() {
// Do your job here which should run every start of day.
}
#Schedule(hour="*/1", minute="0", second="0", persistent=false)
public void someHourlyJob() {
// Do your job here which should run every hour of day.
}
#Schedule(hour="*", minute="*/15", second="0", persistent=false)
public void someQuarterlyJob() {
// Do your job here which should run every 15 minute of hour.
}
}
This is if necessary available in managed beans by #EJB:
#EJB
private BackgroundJobManager backgroundJobManager;
EJB unavailable? Use ScheduledExecutorService
Without EJB, you'd need to manually work with ScheduledExecutorService. The application scoped managed bean implementation would look something like this:
#ManagedBean(eager=true)
#ApplicationScoped
public class BackgroundJobManager {
private ScheduledExecutorService scheduler;
#PostConstruct
public void init() {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
}
#PreDestroy
public void destroy() {
scheduler.shutdownNow();
}
}
where the SomeDailyJob look like this:
public class SomeDailyJob implements Runnable {
#Override
public void run() {
// Do your job here.
}
}
If you don't need to reference it in the view or other managed beans at all, then better just use ServletContextListener to keep it decoupled from JSF.
#WebListener
public class BackgroundJobManager implements ServletContextListener {
private ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent event) {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}
I would like to know if it's ok to use Timer inside application scoped beans.
Example, lets say that I want to create a timer task that sends out a bunch of emails to every registered member one time per day. I'm trying to use as much JSF as possible and I would like to know if this is acceptable (it sounders a bit weird, I know).
Until now I have used all of the above inside a ServletContextListener. (I don't want to use any application server or cron job and I want to keep
the above things inside my web app.)
Is there a smart JSF way of doing this or should I stick with the old pattern?
Introduction
As to spawning a thread from inside a JSF managed bean, it would only make sense if you want to be able to reference it in your views by #{managedBeanName} or in other managed beans by #ManagedProperty("#{managedBeanName}"). You should only make sure that you implement #PreDestroy to ensure that all those threads are shut down whenever the webapp is about to shutdown, like as you would do in contextDestroyed() method of ServletContextListener (yes, you did?). See also Is it safe to start a new thread in a JSF managed bean?
Never use java.util.Timer in Java EE
As to using java.util.Timer in a JSF managed bean, you should absolutely not use the old fashioned Timer, but the modern ScheduledExecutorService. The Timer has the following major problems which makes it unsuitable for use in a long running Java EE web application (quoted from Java Concurrency in Practice):
Timer is sensitive to changes in the system clock, ScheduledExecutorService isn't.
Timer has only one execution thread, so long-running task can delay other tasks. ScheduledExecutorService can be configured with any number of threads.
Any runtime exceptions thrown in a TimerTask kill that one thread, thus making Timer dead, i.e. scheduled tasks will not run anymore. ScheduledThreadExecutor not only catches runtime exceptions, but it lets you handle them if you want. Task which threw exception will be canceled, but other tasks will continue to run.
Apart from the book quotes, I can think of more disadvantages:
If you forget to explicitly cancel() the Timer, then it keeps running after undeployment. So after a redeploy a new thread is created, doing the same job again. Etcetera. It has become a "fire and forget" by now and you can't programmatically cancel it anymore. You'd basically need to shutdown and restart the whole server to clear out previous threads.
If the Timer thread is not marked as daemon thread, then it will block the webapp's undeployment and server's shutdown. You'd basically need to hard kill the server. The major disadvantage is that the webapp won't be able to perform graceful cleanup via e.g. contextDestroyed() and #PreDestroy methods.
EJB available? Use #Schedule
If you target Java EE 6 or newer (e.g. JBoss AS, GlassFish, TomEE, etc and thus not a barebones JSP/Servlet container such as Tomcat), then use a #Singleton EJB with a #Schedule method instead. This way the container will worry itself about pooling and destroying threads via ScheduledExecutorService. All you need is then the following EJB:
#Singleton
public class BackgroundJobManager {
#Schedule(hour="0", minute="0", second="0", persistent=false)
public void someDailyJob() {
// Do your job here which should run every start of day.
}
#Schedule(hour="*/1", minute="0", second="0", persistent=false)
public void someHourlyJob() {
// Do your job here which should run every hour of day.
}
#Schedule(hour="*", minute="*/15", second="0", persistent=false)
public void someQuarterlyJob() {
// Do your job here which should run every 15 minute of hour.
}
}
This is if necessary available in managed beans by #EJB:
#EJB
private BackgroundJobManager backgroundJobManager;
EJB unavailable? Use ScheduledExecutorService
Without EJB, you'd need to manually work with ScheduledExecutorService. The application scoped managed bean implementation would look something like this:
#ManagedBean(eager=true)
#ApplicationScoped
public class BackgroundJobManager {
private ScheduledExecutorService scheduler;
#PostConstruct
public void init() {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
}
#PreDestroy
public void destroy() {
scheduler.shutdownNow();
}
}
where the SomeDailyJob look like this:
public class SomeDailyJob implements Runnable {
#Override
public void run() {
// Do your job here.
}
}
If you don't need to reference it in the view or other managed beans at all, then better just use ServletContextListener to keep it decoupled from JSF.
#WebListener
public class BackgroundJobManager implements ServletContextListener {
private ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent event) {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}
We want to optimize our application. There is some streight linear work going on, that can be executed in multiple threads with smaller working sets.
Our typical service is accessed using the #Inject annotation from within our CDI-managed beans. Also such a service could have it's own dependencies injected, i.e.:
public class MyService {
#Inject
private OtherService otherService;
#Inject
private DataService1 dataService1;
...
public void doSomething() {
...
}
}
Because I can not use #Inject inside the class implementing Runnable. (It's not container managed.) I tried to pass the required services to the class before starting the thread. So, using something like this, makes the service instance (myService) available within the thread:
Class Thread1 implements Runnable{
private MyService myService
public Thread1(MyService myService){
this.myService = myService;
}
public void run(){
myService.doSomething();
}
}
Following the call-hierarchy the call to doStometing() is fine, because a reference to myService has been passed. As far as I understand CDI, the injection is done the moment the attribute is accessed for the first time, meaning, when the doStomething() method tries to access either otherService or dataService1, the injection would be performed.
At that point however I receive an exception, that there is no context available.
I also tried to use the JBossThreadExecuter class instead of Plain-Threads - it leads to the very same result.
So the question would be, if there is a nice way to associate a context (or request) with a created Thread?
For EJB-Beans, I read that marking a method with #Asynchronous will cause the method to be run in a managed thread which itself will be wired to the context. That would basically be exactly what I'm searching for.
Is there a way to do this in CDI?
Or is there any way to obtain a context from within a unmanaged thread?
Weld allows programmatic context management, (there's an example in the official docs).
But before you go this way give EJBs a chance )
#Async invocation functionality is there exactly for your case. And as a bonus you'll get timeout interception and transaction management.
When you kick off an async process, your #RequestScoped and #SessionScoped objects are no longer in scope. That's why you get resolution errors for the injected #RequestScoped objects. Using #Stateless without a CDI scope is essentially #Dependent. You can use #ApplicationScoped objects or if you're on CDI 1.1 you can start up #TransactionScoped.
You have to use JavaEE 7 feature, the managed executor. So it will provide a context for your runnable. I'm not sure if your JBoss version is JavaEE 7 compatible. At least Glassfish 4 is, and that approach works.
See details here
Easiest Solution one can think of is Ejb Async.
They are powerful, does the job and most importantly the concurrency is handled by the container(which could be an issue at some point of time if its not properly managed).
Just a simple use case lets say if we have written a rest service and each request spawns 10 threads(ex using CompletableFuture or anything) to do some long processing tasks and for an instance if 500 requests are made then how will the threads be managed, how the app behaves, does it waits for a thread from the thread pool, what is the timeout period, etc etc and to add to our comfort what happens when the threads are Deamon Threads. We can avoid these overheads to some extent using EJBs.
Its always a good thing to have a friend from the technical services team to help us with all these container specific implementations.
Okay so I have a java app being deployed to JBoss. The application needs to poll an external webservice for jobs. Each job can an should be run on its own thread. This will behave very similar to a jms queue with a pool of mdbs handling the messages. The only real difference is the queue of work is supplied by a restful webservice. So my question is what is the best way to start up my pool of threads or does jboss have a better way of doing this. JMS is not an option.
In theory you shouldn't manage your self thread in Java EE container (in practice it is a bit more relax, if you don't use EJB, JPA or any other container feature).
In Java EE 6 (JBoss 7) you can use Java EE features to do it; you need to leverage the timer feature with the new #Asynchronous EJB call. The only issue is that you don't have persistancy of the async call, if it fails (server crash during processing) the job is lost.
If you need to be sure the job is done, the only Java EE way is persistence JMS (even local one populated with the timer EJB)
Exemple:
#Singleton
#Startup
public class Pool{
#Inject
private AsyncBean aBean;
#Resource
private TimerService timerService;
#Timeout
public void pull(){
try{
// for performance you may get several job and launch several async job
job = getJob() // make your REST call to get the job
// make sure you realy get a job
aBean.async(job)
}finally{
//recreate the timer
timerService.createSingleActionTimer(100, new TimerConfig("timer name", false));
}
}
#PostConstruct
void init(){
timerService.createSingleActionTimer(100, new TimerConfig("timer name", false));
// as timer is created at each start up no need to persist it.
}
}
The async bean:
#Stateless
public class AsyncBean{
#Asynchronous
public void async(Job job){
// do your stuff
}
}