In one hand I've a CronScheduler class which is meant to starts once per application an configure a TimerService.
In the other hand I've a heavy task (annotated as #EJB) which I want to call in the #timeout of the timer. Note that in the timer, I create a thread which calls p.go()
The code:
#Singleton
#Startup
public class CronScheduler {
#EJB
Processor p;
#Resource
private TimerService timerService;
#PostConstruct
public void init() {
String h = ... // h,m ,s work fine
String m = ...
String s = ...
ScheduleExpression conf = new ScheduleExpression();
conf.hour(h);
conf.minute(m);
conf.second(s);
// I've tried with the second param (TimerConfig) enabled and disabled
timerService.createCalendarTimer(conf, new TimerConfig("msg ", false));
LOG.log(Level.INFO, ">> Ready for: " + conf.toString());
}
#Timeout
public void run() {
LOG.log(Level.INFO, "Calling the process");
Thread t = new Thread() {
#Override
public void run() {
super.run();
p.go();
}
};
t.start();
}
}
The point is, the cron is initialize multiple times. The #PostConstruct code runs N times. In the logs I see.
Ready for: A-B-C
Ready for: A-B-C
Ready for: A-B-C
The consequences are p.go() is called multiple times. Is the #singleton annotation working fine?
Perhaps you have more than one timer running? I recently encountered a weird scenario where timer was set to 1k ms and the new one started before the previous one finished. Adding some kind of lock fixed it for me. Maybe it's similar case.
You could debug and check how many threads you have active.
Finally I got; it's a matter of EJB and hand-made threads. The point wasn't the Timer itself but the creation of a new thread which is not handled by the EJB magic.
#Singleton
#Startup
public class CronScheduler {
#EJB
Processor p;
#Resource
private TimerService timerService;
#PostConstruct
public void init() {
String h = ... // h,m ,s work fine
String m = ...
String s = ...
ScheduleExpression conf = new ScheduleExpression();
conf.hour(h);
conf.minute(m);
conf.second(s);
timerService.createCalendarTimer(conf, new TimerConfig("desc msg ", false));
LOG.log(Level.INFO, ">> Ready for: " + conf.toString());
}
#Timeout
public void run() {
LOG.log(Level.INFO, "Calling the process");
p.go();
}
}
Related
Hopefully I can make some sense, I've never done this particular task before.
I have an application where I want to create a bean on startup that has a scheduled task that runs every 30 minutes and updates a Map that is used by all sessions in the application. My initial thought was to create an ApplicationScoped bean for this task.
So the idea is this:
User A logs in. Stores value in his Map.
User B logs in. Stores value in his Map.
Process runs, updates all values in map.
User B and A will check their value constantly throughout the session.
Logout, remove value from map.
So right now it looks like this:
#ManagedBean(eager=true, name="monitor")
#ApplicationScoped
public class MyMonitor implements Serializable {
private static final long serialVersionUID = -1L;
private ScheduledExecutorService scheduler;
private HashMap<Integer, String> myDict;
#PostConstruct
public void init() {
myDict = new HashMap<Integer, String>();
myDict.put(1, "a");
myDict.put(2, "b");
myDict.put(3, "c");
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 30, TimeUnit.SECONDS);
}
#PreDestroy
public void destroy() {
scheduler.shutdownNow();
}
public class SomeDailyJob implements Runnable {
#Override
public void run() {
System.out.println("hello world");
}
}
public HashMap<Integer, String> getMyDict() {
return myDict;
}
public void setMyDict(HashMap<Integer, String> myDict) {
this.myDict = myDict;
}
}
In another class, I need to somehow retrieve the value from myDict based on key (this class is in the DAO layer, it is not a managed bean). I tried to instantiate this bean in that class:
public class MyDAO {
#ManagedProperty(value="#{myMonitor}")
private MyMonitor monitor;
}
And got:
WARNING: The web application [app] is still processing a request that has yet to finish
My questions are this:
Should I actually use an ApplicationScoped bean for this problem?
I do not have EJB.
I know I haven't added the synchronicity yet,
but is this safe? Can this actually work?
You can use a java.util.Timer for this. Define a class
import java.util.TimerTask;
public class Monitor extends TimerTask {
#Override
public void run() {
// do something
}
}
then your class may be refactored to something like (I removed other code to keep just the idea)
#ManagedBean(eager=true, name="monitor")
#ApplicationScoped
public class MyMonitor implements Serializable {
//runs as daemon thread
private final Timer timer = new Timer(true);
private Monitor monitor = new Monitor();
#PostConstruct
public void init() {
// period are in milliseconds
timer.scheduleAtFixedRate(monitor, 0, 30*1000);
}
#PreDestroy
public void destroy() {
timer.cancel();
}
}
This will help you also to move most of the update logic in the Monitor.run() separating it from the scheduler logic. I hope it helps.
I have a singleton that needs to start a scheduled execution. This is the code:
public enum Service{
INSTANCE;
private Service() {
startAutomaticUpdate();
}
private void startAutomaticUpdate() {
try {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(new AutomaticUpdate(), 0, 15, TimeUnit.MINUTES);
} catch (Exception e) {
LOG.error(e.getMessage() + "Automatic update not working: ");
}
}
//Makes a call to a webservice that updates a static variable.
private void getTemplateNames(){...}
private class AutomaticUpdate implements Runnable {
public AutomaticUpdate() {
}
#Override
public void run(){
try{
getTemplateNames();
}catch(Exception e){
LOG.error("Error in automatic update: "+e.getMessage());
}
}
}
I am not sure when or if I should call the shutdown method of the executor. I'm using JEE5, so I'm not sure if simply undeploying the app will automatically execute the shutdown, or if I am messing up big time and creating a ridiculous amount of threads and not killing them.
-EDIT-
I'll add a bit more info, just in case.
The whole app is a RESTful web app using Jersey as a ServletContainer.
You said JEE5? Why you're reeinventing the wheel?
Just create a EJB with #Schedule and #Startup
#Singleton
#Startup
public class TaskSingleton {
#Schedule(second = "0", minute = "*/15", hour = "*")//This mean each 15:00 minutes
public void getTemplateNames() {
// YOUR TASK IMPLEMENTATION HERE
}
}
No you don't mean JEE5 complaint server. :(
Go for the implementation with a ServletContextListener. I wrote some answer like that here, It's the same idea, it does applies here.
I am trying to use the ScheduledExecutorService to run every few seconds in EJB. However, it does seem to work. I am not sure if I am doing anything wrong. I found this website: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html.
I want to run some code every few seconds. I am not sure whether this is concurrency because I want to execute only on one Thread that runs repeately. Below is the code:
#Startup
#Singleton
public class StartUp {
private ScheduledExecutorService executor;
#PostConstruct
public void start() {
executor = Executors.newScheduledThreadPool(1);
Runnable runnable = new Runnable() {
public void run() {
while(true) {
System.out.println("i");
// after send an e-mail
}
}
};
ScheduledFuture<?> scheduledFuture = executor.scheduleAtFixedRate(runnable, 0, 1, TimeUnit.SECONDS);
}
}
This does not seem to run. What am I doing wrong?
Any ideas?
When using EJBs you shouldn't create your own thread pool, but let the container do that for you. You should have something similar to:
#Singleton
public class TimerService {
#EJB
HelloService helloService;
#Schedule(second="*/1", minute="*",hour="*", persistent=false)
public void doWork(){
System.out.println("timer: " + helloService.sayHello());
}
}
I try to get an async process running.
Based on this example: http://tomee.apache.org/examples-trunk/async-methods/README.html
But the method addWorkflow(Workflow workflow) will only return when the code in run(Workflow workflow) is fully completed.
Then when it returns and result.get(); is called I'll get the exception:
Caused by: java.lang.IllegalStateException: Object does not represent an acutal Future
Any suggestion what I'm missing?
#Singleton
public class WorkflowProcessor {
#EJB
private WorkflowManager workflowManager;
private final static Logger log = Logger.getLogger(WorkflowProcessor.class.getName());
public void runWorkflows(Collection<Workflow> workflows) throws Exception{
final long start = System.nanoTime();
final long numberOfWorkflows = workflows.size();
Collection<Future<Workflow>> asyncWorkflows = new ArrayList<>();
for(Workflow workflow : workflows){
Future<Workflow> w = addWorkflow(workflow);
asyncWorkflows.add(w);
}
log.log(Level.INFO, "workflow jobs added {0}", new Object[]{numberOfWorkflows});
for(Future<Workflow> result : asyncWorkflows){
result.get();
}
final long total = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start);
log.log(Level.INFO, "WorkflowProcessor->runWorkflows {0} workflows completed in:{1}", new Object[]{numberOfWorkflows, total});
}
#Asynchronous
#Lock(LockType.READ)
#AccessTimeout(-1)
private Future<Workflow> addWorkflow(Workflow workflow){
run(workflow);
return new AsyncResult<Workflow>(workflow);
}
private void run(Workflow workflow){
this.workflowManager.runWorkflow(workflow);
}
So the normal way would be to have the #Asynchronous method in another bean from the caller method.
#Stateless
public class ComputationProcessor {
#Asynchronous
public Future<Data> performComputation {
return new AsyncResult<Data>(null);
}
}
#Stateless
public class ComputationService {
#Inject
private ComputationProcessor mProcessor;
public void ...() {
Future<Data> result = mProcessor.performComputation();
...
}
}
As you discovered, it won't work if the #Asynchronous method is in the same bean than the caller.
The issue is that Java can't decorate the implicit this pointer.
In other words, the #Asynchronous annotation won't be processed and you're doing an ordinary method call.
You can inject your so singleton with a reference to itself (call this e.g. "self"), then call self.addWorkflow.
You might also want to consider running your async code in a stateless bean. You are using a read lock for addWorkflow, but runWorkflow still has a write lock. I think you have a dead lock now: you're holding the lock until work is done, but no work can be done until the write lock is released.
I want to write a back-ground job (EJB 3.1), which executes every minute. For this I use the following annotation:
#Schedule(minute = "*/1", hour = "*")
which is working fine.
However, sometimes the job may take more than one minute. In this case, the timer is still fired, causing threading-issues.
Is it somehow possible, to terminate the scheduler if the current execution is not completed?
If only 1 timer may ever be active at the same time, there are a couple of solutions.
First of all the #Timer should probably be present on an #Singleton. In a Singleton methods are by default write-locked, so the container will automatically be locked-out when trying to invoke the timer method while there's still activity in it.
The following is basically enough:
#Singleton
public class TimerBean {
#Schedule(second= "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() throws InterruptedException {
System.out.println("Called");
Thread.sleep(10000);
}
}
atSchedule is write-locked by default and there can only ever be one thread active in it, including calls initiated by the container.
Upon being locked-out, the container may retry the timer though, so to prevent this you'd use a read lock instead and delegate to a second bean (the second bean is needed because EJB 3.1 does not allow upgrading a read lock to a write lock).
The timer bean:
#Singleton
public class TimerBean {
#EJB
private WorkerBean workerBean;
#Lock(READ)
#Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() {
try {
workerBean.doTimerWork();
} catch (Exception e) {
System.out.println("Timer still busy");
}
}
}
The worker bean:
#Singleton
public class WorkerBean {
#AccessTimeout(0)
public void doTimerWork() throws InterruptedException {
System.out.println("Timer work started");
Thread.sleep(12000);
System.out.println("Timer work done");
}
}
This will likely still print a noisy exception in the log, so a more verbose but more silently solution is to use an explicit boolean:
The timer bean:
#Singleton
public class TimerBean {
#EJB
private WorkerBean workerBean;
#Lock(READ)
#Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() {
workerBean.doTimerWork();
}
}
The worker bean:
#Singleton
public class WorkerBean {
private AtomicBoolean busy = new AtomicBoolean(false);
#Lock(READ)
public void doTimerWork() throws InterruptedException {
if (!busy.compareAndSet(false, true)) {
return;
}
try {
System.out.println("Timer work started");
Thread.sleep(12000);
System.out.println("Timer work done");
} finally {
busy.set(false);
}
}
}
There are some more variations possible, e.g. you could delegate the busy check to an interceptor, or inject a singleton that only contains the boolean into the timer bean, and check that boolean there, etc.
I ran into the same problem but solved it slightly differently.
#Singleton
public class DoStuffTask {
#Resource
private TimerService timerSvc;
#Timeout
public void doStuff(Timer t) {
try {
doActualStuff(t);
} catch (Exception e) {
LOG.warn("Error running task", e);
}
scheduleStuff();
}
private void doActualStuff(Timer t) {
LOG.info("Doing Stuff " + t.getInfo());
}
#PostConstruct
public void initialise() {
scheduleStuff();
}
private void scheduleStuff() {
timerSvc.createSingleActionTimer(1000l, new TimerConfig());
}
public void stop() {
for(Timer timer : timerSvc.getTimers()) {
timer.cancel();
}
}
}
This works by setting up a task to execute in the future (in this case, in one second). At the end of the task, it schedules the task again.
EDIT: Updated to refactor the "stuff" into another method so that we can guard for exceptions so that the rescheduling of the timer always happens
Since Java EE 7 it is possible to use an "EE-aware" ManagedScheduledExecutorService, i.e. in WildFly:
In for example a #Singleton #Startup #LocalBean, inject the default "managed-scheduled-executor-service" configured in standalone.xml:
#Resource
private ManagedScheduledExecutorService scheduledExecutorService;
Schedule some task in #PostConstruct to be executed i.e. every second with fixed delay:
scheduledExecutorService.scheduleWithFixedDelay(this::someMethod, 1, 1, TimeUnit.SECONDS);
scheduleWithFixedDelay:
Creates and executes a periodic action that becomes enabled first
after the given initial delay, and subsequently with the given delay
between the termination of one execution and the commencement of the
next.[...]
Do not shutdown the scheduler in i.e. #PreDestroy:
Managed Scheduled Executor Service instances are managed by the
application server, thus Java EE applications are forbidden to invoke
any lifecycle related method.
well I had a similar problem. There was a job that was supposed to run every 30 minutes and sometimes the job was taking more than 30 minutes to complete in this case another instance of job was starting while previous one was not yet finished.
I solved it by having a static boolean variable which my job would set to true whenever it started run and then set it back to false whenever it finished. Since its a static variable all instances will see the same copy at all times. You could even synchronize the block when u set and unset the static variable.
class myjob{
private static boolean isRunning=false;
public executeJob(){
if (isRunning)
return;
isRunning=true;
//execute job
isRunning=false;
}
}