I have a spring boot application which has two beans - AppState and Users.
AppState depends on the bean Users as it autowires it. The skeleton codes for the two beans are as follows.
#Component
#EnableScheduling
public class Users {
#Getter // lombok
private List<String> users;
#PostConstruct
public void init(){
users = new ArrayList<>();
load(); // I removed this later
}
#Scheduled(fixedRate = 3600000)
public void load(){
// load list of users from (say) a file and populate ArrayList 'users'
// this method takes at least 3 mins to finish
}
}
AppState is
#Component
public class AppState {
#Atowired
private Users users;
public List<String> getUsers(){
return users.getUsers();
}
}
I noticed that the method load() in Users was getting triggered twice - probably once during init() and the other time while scheduling load() right after Users bean had been created. So I removed the call to load() in init(). This fixed the redundant call issue.
However, now I find that my service starts as soon as AppState and Users beans have been created, even though Users has not been populated with data yet. This is risky for me as the service, during this time, will return 0 users if queried.
I need help with ANY of the following.
Should I move load() back into init() to make sure that when the bean is done with PostConstruct, it does have all users info? If I go this route, how can I prevent redundant run of load()?
If load() should stay out of init(), how can I ensure that AppState is not ready unless Users has executed load()? I tried using the following code in AppState but it just hangs.
The code is as follows.
#PostConstruct
public void appStateInit(){
while(users.getUsers().size()==0){
try{
Thread.sleep(10000); // sleep 10s
}catch(whatever){
}
}
}
I would suggest having a flag in the class and setting it to true once init() has finished. You can skip the execution of load() if flag is not set yet, e.g.:
private AtomicBoolean shouldExecute;
#PostConstruct
public void init(){
users = new ArrayList<>();
shouldExecute = true;
}
#Scheduled(fixedRate = 3600000)
public void load(){
if(shouldExecute){
// load list of users from (say) a file and populate ArrayList 'users'
// this method takes at least 3 mins to finish
}
}
Also, another solution will be to configure initialDelay in #Scheduled annotation (documentation here) which would delay the first execution by configured number of milliseconds, e.g:
#Scheduled(fixedRate = 3600000, initialDelay=180000)
public void load(){
// load list of users from (say) a file and populate ArrayList 'users'
// this method takes at least 3 mins to finish
}
Related
I have a Java application that runs several scheduler to get and provide data to an external application. I will have to add another scheduler to get data from another external application. That would be the exact same process as one of the scheduler already existing for the first application.
So roughly it would be something like this:
However I have small confidence in the formatting of the data of this second application, I know that they have less verifications that the fist application and I might get funny things. I will obviously put plenty of null/bad format check on my side, but I have to make sure that if they ever send me bad data this doesn't impact my others schedulers.
#EnableScheduling
public class myApp{
#Scheduled(fixedRate = 1000)
public void externalApp1() {
do stuff...
commonMethod();
}
#Scheduled(fixedRate = 1000)
public void externalApp2() {
do stuff...
commonMethod();
}
public void commonMethod(){
doStuff...
}
}
One of my first idea is to put dedicated threads to each scheduler, so that if they send bad data and it ends up killing the thread for whatever reason, it only impacts their own process and not the schedulers for the first external application. I have done this for now based on what I found, I suppose this should work as intended:
#Configuration
#EnableAsync
#EnableScheduling
public class MyApp{
#Scheduled(fixedRate = 1000)
#Async(value = "threadPool1")
public void externalApp1() {
dostuff...
commonMethod();
}
#Scheduled(fixedRate = 1000)
#Async(value = "threadPool2")
public void externalApp2() {
dostuff...
commonMethod();
}
public void commonMethod(){
doStuff...
}
#Bean
public Executor threadPool1() {
return Executors.newFixedThreadPool(1);
}
#Bean
public Executor threadPool2() {
return Executors.newFixedThreadPool(1);
}
}
(actual code would be with beans properly separated from main class)
But I am wondering if there is any other way to fully ensure the processes are totally independant from one another?
EDIT: I precise that the data I get from the second application are not used for any process of the first application. It has a process on its own and data are not shared between those 2 external applications
I have a method that should periodically update records in a database.
#Service
public class MyService {
#Autowired
private MyRepository myRepository;
private Boolean flag = false;
#Transactional
public int method1(Args args) {
// do something
if (!flag) {
method2()
}
return x;
}
#Transactional
public int method2(Args args) {
polling = true;
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
List<Records> records = myRepository.getRecords()
for (Record record : records ) {
// prints the Id of each record. Now, they are all have Id=1
System.out.println(record.getId());
// setting the record's Id to 5
record.setId(5);
// prints '5'
System.out.println(record.getId());
}
}
}, 10, 1000*60*4
}
}
Method1 calls Method2. Method2 executes the code inside the run() function every 4 minutes. The code inside run() works properly without scheduling (gets the Ids for each record, prints them, updates the db by setting Id to 5).
However, now, with my use of TimerTask, it still retrieves and prints the Ids, supposedly sets each record's Id to 5, and even prints out '5' at record.get(Id) which would lead me to believe the database was successfully updated with the new Id.
When I actually check my database, I find that the Ids actually haven't been updated to 5. The original Ids remain.
I'm not sure why this is happening, as it seemed like the Ids were being updated. Is this something to do with TimerTask creating a new thread?
The #Transational assumes that it is going to wrap ONE TRANSACTION against the DB, so you need to have your #Transactional functions where they do one thing, let and get out immediately. You know the DB will have either committed or rolled back. Depending on Transaction Isolation levels (another topic you may want to research, but probably don't need to) the thnigs that go on inside the #Transactional never get written to db until that function actually returns. That's probably all you are missing. Chrylis is right to use #Scheduled for 'repeating things' but the real problem is the one i stated, with all due respect to him/her.
Summary: Make your #Scheduled function call a #Transactional function (for each DB transaction you want to do), and then it will work.
I have a stateless bean that insert some data using asynchronous method of other bean ( local injection). This data insertion takes a time , so I do not wait to finish for this operation. After this data insertion, I am calling another method of same bean. When I put a debug point to method, server waits for approximately 90 seconds to reach this point. May be Jboss waits for transaction to complete for asynchronous method. I do not know what is going on. .
#Stateless
public class SimulationNodePersistenceBean implements SimulationNodePersistenceRemote, SimulationNodePersistenceLocal {
#Resource
SessionContext context;
#EJB
private SimulationResultGraphPersitenceBean graphPersistenceBean;
#Asynchronous
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void addResultGraphsToDatabase(long id, Graph[] graphList) {
ResultGraph paramGraph;
ResultGraphPoint dataPoint;
Graph graph;
for (int i = 0; i < graphList.length; i++) {
graph = graphList[i];
paramGraph = new ResultGraph();
try {
graphPersistenceBean.persistGraph(paramGraph);
} catch (Exception databaseException) {
// TODO add error message to the contingency simulation messages
// list
logger.error("Error saving ResultGraph:" + paramGraph);
}
}
long duration = System.nanoTime() - startTime;
logger.debug("Graphs inserted to DB in (sec) :" + (duration / NANO_SECOND_CONVERSION_FACTOR));
}
// #Asynchronous
public void persistSimulationResults(long contingencySimulationId, Graph[] graphList,
List<AB> reiList) {
if (graphList != null) {
addResultGraphsToDatabase(contingencySimulationId, graphList);
}
if (reiList != null) {
//another method
}
calculateContSimStability(contingencySimulationId);
}
#Override
public void calculateSimIndex(long id) {
}
This is other bean called from main bean
#Stateless
public class SimulationResultGraphPersitenceBean {
#PersistenceContext(unitName = "DBService")
private EntityManager em;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
#Asynchronous
public void persistGraph(ResultGraph graph) throws SiGuardPersistenceException {
try {
ResultGraphService service = new ResultGraphService(em);
service.create(graph);
em.flush();
} catch (Exception ex) {
throw new PersistenceException("Error persisting graph", ex);
}
}
This is client calls main bean.This works asynchronously.
getSimulationEJB().persistSimulationResults(id, tsaParser.getLstFile().getGraphArray());
After calling this method, I call another method of SimulationNodePersistenceBean.This method waits for some minutes.
getSimulationEJB().calculateSimIndex(contSimId);
I have created a thread dump using jstack. Actually I do not have this problem in Jboss As 6. I migrated my application to Jboss EAP 6. 4. May be I need to make some configuration changes in configuration. But I do not know what should I do.
I checked thread dump. I did not find any thread in BLOCKING state. Should I look for other keywords?
As I already pointed out in the comments, you are mixing the calling of Asynchronous and Synchronous methods. In your example, you are calling the addResultGraphsToDatabase method (Which is a Asynch method) from persistSimulationResults method (which is a synch method - since you have commented out the asynchronous annotation on top of it). Therefore, right now the addResultGraphsToDatabase method is behaving like a Synchronous method despite the Asynchronous annotation.
I am not sure if you took a look at the link that I posted in the comments but you need to call the Asynch method using the SessionContext. Something like this:
At the class level:
#Inject
SessionContext ctx;
The, within the persistSimulationResults method:
ctx.addResultGraphsToDatabase
For a more detailed example, please take a look at the link I have posted in the comments.
I am currently trying to make a hibernate query inside of a TimerTask (Runnable). This task makes no saves or updates to the database. It just retrieves a list of jobs. Anytime I run this task, I get HibernateException: Unable to locate current JTA transaction.
I believe this has to do with the fact that it's being started from a runnable because I use this same query outside of this TimerTask.
I can't share the code I am working with because it is for work and proprietary. My research on this issue has only really led me to solutions with Spring, but I am not able to use Spring for this work.
I will attempt to make some pseudo code.
public class JobManager extends TimerTask {
#Override
public void run() {
...
List<String> jobs = Handler.getJobs();
...
}
}
public class Handler {
public static List<String> getJobs() {
return DAO.getJobs();
}
}
public class DAO {
public List<Object> getJobs() {
try {
session = HibernateManager.getSessionFactory().getCurrentSession();
Query myQuery = session.createQuery("query string");
List = myQuery.list();
} catch(HibernateException he) {
log.error(he);
}
return list;
}
}
The exception occurs when the runnable calls getJobs(). This method work everywhere else outside of the TimerTask.
I understand that this is limited information to work with. I can try to accommodate for any other information if it is needed.
I believe every transaction has some time out, so you can not put the regular timer task code inside the running transaction. As it is just reading the data you wont need to start the transaction, just session is enough
I have encountered the same problem and solved by creating the new session
session = sessionFactory.openSession();
EDIT
session.getCurrentSession() takes the current session from the current thread, so it wont work inside timer task. Use openSession()
I work on a project that makes service for mobile apps and also
I should make a project that monitor the Mobile Project.
I want to make some reports that show how many messages come in this moment
and some other reports like that.
but I don’t want to get queries in monitoring project directly from DB.
I want to make a temporary data holder in memory and save the last 10 minutes
data on it (like a variable or a list)
but I don’t know technically how?
I use Spring and Hibernate in my project.
First of all we assume that our program tries to refresh the reports of an entity called SampleEntity every 10 minutes. This is just a simple POJO.
public class SampleEntity
{
// your fields and their getters and setters
}
Next we have a class, I call it SampleEntityDA, which queries the records we need for our reports from db. As you use hibernate you can simply return the result as java.util.List (I think this is one your main problems).
public class SampleEntityDA
{
public List<SampleEntity> queryFromDB()
{
// fetch records you need for your reports here
Session session = ...
return session.createQuery("from sampleEntity").list();
}
}
And at last...
query from db every 10 minutes...
To query from db every 10 minutes, you can simply use java.util.Timer class.
public class ReportTimer extends Observable
{
private Timer timer;
public static void main(String[] args)
{
// Your program starts from here
new ReportTimer().start();
}
private void start()
{
// schedule method of Timer class can execute a task repeatedly.
// This method accepts a TimerTask interface instance as its first parameter.I implement
// it as an anonymous class. TimerTask interface has a run method. Code in this method will execute repeatedly.
// Its second parameter is delay before task gets started to execute.
// And its third parameter is the interval between each execution(10min in your case)
timer = new Timer();
timer.schedule(
new TimerTask()
{
#Override
public void run()
{
notifyObservers(
new SampleEntityDA().queryFromDB() // 10 minutes passed from the last query, now its time to query from db again...
);
}
}, 100, 600000); // 600000ms = 10min
}
public void finish()
{
// call me whenever you get tired of refreshing reports
timer.cancel();
}
}
At last you need to update the data holder of your reports every 10min.
You can do this simply by Observer Pattern. As you know in java this is done by Observer class and Observable interface.
So 1) ReportTimer needs to extend Observer class and 2) in TimerTask we need to notify the listeners; this is done by notifyObservers method.
Our last class has duty of refreshing reports. I call it ReportGenerator. This class refreshes the reports whenever you like. It also has a java.util.List field that has the most recent data of db. ReportGenerator updates this field whenever its Observer - I mean ReportTimer - notifies it.
public class ReportGenerator implements Observer
{
List<SampleEntity> list = new ArrayList<SampleEntity>();
#Override
public void update(Observable o, Object arg)
{
// This method will automatically!?! executed whenever its observer notifies him.
// The arg parameter consists the new records. you just need to put it in the list field.
List<SampleEntity> list = (List<SampleEntity>) arg;
}
public void refreshReport()
{
// you can easily refresh a report with data in list field
}
public void refreshAnotherReport()
{
// you can easily refresh a report with data in list field
}
}
use map, hashMap, or ConcurrentHashMap.
make a crone job that update Map after ten min.
Here is a link for map, HashMap, ConcurrentHashMAP