Hi every one i am having an issue with timer service, on timeout it perform some business logic if there is any exception in business logic. which is catched in one of interceptor as well as in timer service. then timer service is not canceled. timer.cancel();
So how it works my timer service get exectued on timeout, it calls an ejb function, this ejb has an interceptor associated with it. if ejb function has any exception. Interceptor is basically logging that exception. then i have a code which stops the timer, it should work in case of success or failure, but it only stop timer in case of success. in case of failure(when exception occurs) it does not cancel the timer. so every time i restart jboss it try to excute the timer again (as it was failed).
My Question is how can i stop timer in case of success and failure(exception). Please note i am using Interceptor as well (Which i can not remove, while removing it fixes the issue).
Here is my different code classes which may help in understanding the issue.
Business Logic Bean
#Stateless
#Local(UtilityLocal.class)
#Interceptors({ ExceptionInterceptor.class })
public class UtilityEJB implements UtilityLocal {
public void doDomeThing(MazTimerTask task) {
System.out.println("--- Business logic ---");
Integer x = 5/0; // this will generate an exception
System.out.println("--- Business logic ---");
}
}
Interceptor
public class ExceptionInterceptor {
#Resource
private javax.ejb.SessionContext ctx;
#AroundInvoke
public Object aroundInvoke(final InvocationContext invocationContext)
throws Exception { //NOPMD
try {
return invocationContext.proceed();
}
catch (Exception exception) {
System.out.println(" Logg the exception here");
throw exception;
}
}
}
Timer Service
#Stateless
public class MazTimer implements MazTimerLocal, MazTimerRemote{
#EJB
private transient UtilityLocal ejb;
#Resource
private transient TimerService timerService;
#Timeout
#TransactionTimeout(3600)
public void handleTimeout(Timer timer) {
MazTimerTask task = (MazTimerTask) timer.getInfo();
if (task != null ) {
try{
ejb.doDomeThing(task);
}catch(Exception e) {
System.out.println("------------ Exception occured : " + task.getName());
}
finally {
stopTimer(task);
}
}
}
public void startTimer(MazTimerTask task) {
timerService.createTimer(new Date(), 10, task);
}
private void stopTimer(MazTimerTask task) {
try {
Timer timer = getTimer(task);
if (timer != null) {
timer.cancel();
System.out.println("------------ Timer stopped : " + task.getName());
}
} catch (RuntimeException e) {
}
}
private Timer getTimer(Serializable timerId) {
Timer timer = null;
if (timerId != null) {
Iterator<Timer> it = timerService.getTimers().iterator();
while (it.hasNext()) {
Timer currentTimer = it.next();
if (currentTimer.getInfo().equals(timerId)) {
timer = currentTimer;
break;
}
}
}
return timer;
}
}
Related
So basically I have a task with a delay that kills a VPN pod. I don't want to have a running pod when it's not needed.
The Desired behavior is when the service receives a request(REST) it cancels the existing task and creates a new one with further delay.
In my solution I use thread.stop() to cancel my task which has been deprecated for a while.
...
var VPN_TIMER_THREAD_NAME = "vpn-timer";
for (var thread : Thread.getAllStackTraces().keySet()) {
if (thread.getName().equals(VPN_TIMER_THREAD_NAME)) {
// Interrupted doesn't work for me
thread.stop();
}
}
var timer = new Timer(VPN_TIMER_THREAD_NAME);
timer.schedule(new TimerTask() {
#Override
public void run() {
// New Transaction for EM
TransactionStatus tx = VpnServiceImpl.this.txManager.getTransaction(new DefaultTransactionDefinition());
try {
var vpnToUpdate = VpnServiceImpl.this.em.find(Vpn.class, vpn.getId());
doTearDown(vpnToUpdate);
VpnServiceImpl.this.txManager.commit(tx);
} catch (RuntimeException e) {
log.error("Tear Down Error {}.", e.getMessage());
VpnServiceImpl.this.txManager.rollback(tx);
}
}
}, this.vpnProperties.delay());
...
private VpnStatusS2SDto doTearDown(Vpn vpn) {
log.debug("In the tear down");
this.client
.pods()
.inNamespace(this.kubeProps.getNamespace())
.withLabel("app", "vpn-gateway")
.withLabel("app.kubernetes.io/component", "vpn")
.delete();
entity.setModifiedDate(Instant.now());
this.em.persist(entity);
return mapper.toVpnStatusDto(entity);
}
When I'm changing to thread.interrupt() the doTearDown method is invoking more than once if I make more than one request.
With thread.stop it "kills" the previous task and creates a new one, indeed the tear down has been invoked only once.
I'm using Spring Boot.
Is there any way to implement that behavior?
Thanks in advance
According to the answer from ewramner I found the solution. It works as expected. Every new request cancels the existing task and creates a new one.
I've created the nested task class:
private class ShutDownTask extends TimerTask {
private final Vpn vpn;
private final PlatformTransactionManager txManager;
private final EntityManager em;
ShutDownTask(Vpn vpn, PlatformTransactionManager txManager, EntityManager em) {
this.vpn = vpn;
this.txManager = txManager;
this.em = em;
}
#Override
public void run() {
TransactionStatus tx = this.txManager.getTransaction(new
DefaultTransactionDefinition());
try {
var vpnToUpdate = this.em.find(Vpn.class, this.vpn.getId());
doTearDown(vpnToUpdate);
this.txManager.commit(tx);
} catch (RuntimeException e) {
this.txManager.rollback(tx);
}
}
}
In my service class:
#Service
public class VpnServiceImpl {
...
private final PlatformTransactionManager txManager;
private final EntityManager em;
private ShutDownTask shutDownTask;
...
if (this.shutDownTask != null) {
this.shutDownTask.cancel();
}
var timer = new Timer("vpn-timer");
this.shutDownTask = new ShutDownTask(vpn, this.txManager, this.em);
timer.schedule(this.shutDownTask, this.vpnProperties.delay());
...
}
I have singleton client with the below contract
public interface MQPublisher {
void publish(String message) throws ClientConnectionException, ClientErrorException;
void start() throws ClientException;
void stop();
}
The class which is using this publisher is as below :
public class MessagePublisher {
#Autowired
private MQPublisher publisher;
private AtomicBoolean isPublisherRunning;
public void startPublisher() {
if (!isPublisherRunning.get()) {
publisher.start();
isPublisherRunning.compareAndSet(false, true);
}
}
#Retry(RETRY_MSG_UPLOAD)
public void sendMessage(String msg) {
try {
startPublisher();
publisher.publish(msg); // when multiple requests fail with the same exception, what will happen??
} catch (Exception e) {
log.error("Exception while publishing message : {}", msg, e);
publisher.stop();
isPublisherRunning.compareAndSet(true, false);
throw e;
}
}
We are using resilience4j retry functionality to retry the sendMessage method. This works fine in case of a single request. Consider a case when multiple requests are processed parallely and all of them fails with an exception. In this case, these requests will be retried and there is a chance that one thread will start the publisher while the other will stop it and it will throw exceptions again. How to handle this scenario in a cleaner way?
It isn't clear why the whole publisher should be stopped in case of failure. Nevertheless, if there are real reasons for that, I would change the stop method to use an atomic timer that will restart on each message sending and stop the publisher only after at least 5 seconds (or the time needed for a message to be successfully sent) have passed from the message sending.
Something like that:
#Slf4j
public class MessagePublisher {
private static final int RETRY_MSG_UPLOAD = 10;
#Autowired
private MQPublisher publisher;
private AtomicBoolean isPublisherRunning;
private AtomicLong publishStart;
public void startPublisher() {
if (!isPublisherRunning.get()) {
publisher.start();
isPublisherRunning.compareAndSet(false, true);
}
}
#Retryable(maxAttempts = RETRY_MSG_UPLOAD)
public void sendMessage(String msg) throws InterruptedException {
try {
startPublisher();
publishStart.set(System.nanoTime());
publisher.publish(msg); // when multiple requests fail with the same exception, what will happen??
} catch (Exception e) {
log.error("Exception while publishing message : {}", msg, e);
while (System.nanoTime() < publishStart.get() + 5000000000L) {
Thread.sleep(1000);
}
publisher.stop();
isPublisherRunning.compareAndSet(true, false);
throw e;
}
}
}
I think it is important to mention (as you just did) that this is a terrible design, and that such calculations should be done by the publisher implementer and not by the caller.
I have problem with receiving new messages from my JS client after I use the first received message in new thread and cancel the thread. I use spring boot for the back end. The interesting thing is that the session is not closed but I just cannot receive any more messages after the first one when I interrupt my thread.
Here is my websocket config:
#Configuration
#EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new WebSocketHandler(), "/socket1").setAllowedOrigins("*");
}
}
Here is my handler with the executor service:
public class WebSocketHandler extends AbstractWebSocketHandler {
Logger logger = LoggerFactory.getLogger(WebSocketHandler.class);
Test test = new Test();
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
logger.info("START");
List<UrlWithPageNumber> listings = new ArrayList<>();
listings.add(new UrlWithPageNumber( "www.somesite.com", 1));
listings.add(new UrlWithPageNumber( "www.anothersite.com", 1));
listings.add(new UrlWithPageNumber( "www.thirdsite.com", 1));
checkItemsAsync(listings, session);
logger.info("DONE");
session.sendMessage(new TextMessage("DONE"));
}
public void checkItemsAsync(List<UrlWithPageNumber> listings, WebSocketSession session) {
ExecutorService executorService = Executors.newFixedThreadPool(1);
final CountDownLatch latch = new CountDownLatch(listings.size());
for (UrlWithPageNumber listing : listings) {
executorService.submit(() -> {
if(Test.stop) {
return;
}
ListingInfo listingInfo = test.itemPage(listing.getLink(), 1, 1);
logger.info(listingInfo.toString());
synchronized(session) {
try {
session.sendMessage(new TextMessage(listingInfo.toString()));
} catch (IOException e) {
e.printStackTrace();
}
}
latch.countDown();
});
}
try {
latch.await();
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
}
}
Now the problem is the following: I call my handleTextMessage method from JS client and the execution is starting then I press another button in my page and it is changing Test.stop boolean flag to true and in that way i stop the remaining threads to be executed. After that if I call handleTextMessage from the js like the first time it is not called. I checked if I close the WebSocketSession and then try to call the backend and the result is similar but in my case the session is not closed for sure ! The question is how to use the WebSocketSession many times and why the session is become broken when I use it in my executor service and stop the thread? Should I do something with the session if I shutdown threads or this is just some spring boot bug ?
The problem is in the latch it wait more than expected because I skip some threads..
I do create a timer which start when i deploy my application, what i note is this timer not stop when i Undeploy my application?
How can this happen, and show me the result in Output netbeans?
Should i restart my server every time that i Undeploy my
application?
Singleton
#Singleton
#Startup
public class StartWhenDeploy {
private static final int PERIOD = 3000;
#PostConstruct
public void init() {
System.out.println("I will set information to start my task");
Timer timer = new Timer();
timer.schedule(new TimerAction(1), new Date(), PERIOD);
}
}
TimerTask
public class TimerAction extends TimerTask {
public int nbrUsers;
public TimerAction(int nbrUsers) {
this.nbrUsers = nbrUsers;
}
#Override
public void run() {
System.out.println("This task is planified to execute at " + new Date());
System.out.println("Creation " + (createUser() ? "------------Success------------" : "------------Failed------------"));
}
public boolean createUser() {
try {
System.out.println("-------------->" + nbrUsers);
for (int i = 0; i < nbrUsers; i++) {
System.out.println("Create user >>>>" + i);
}
return true;
} catch (Exception e) {
System.out.println("Exception " + e);
return false;
}
}
}
It still show me the result like this in Output netbeans:
...
Infos: This task is planified to execute at Wed Nov 16 14:40:29 GMT+01:00 2016
Infos: -------------->1
Infos: Create user >>>>0
Infos: Creation ------------Success------------
...
Someone have an idea about this issue?
Thank you.
In GlassFish (in JavaEE in general), you should use the TimerService from the EJB specification for scheduling. I assume you are using java.util.Timer, which just runs in a separate thread. GlassFish does not know anything about the thread, so it cannot stop it with undeploy.
You should rewrite your Singleton to something like this:
#Singleton
#Startup
public class StartWhenDeploy {
private static final int PERIOD = 3000;
// Inject the TimerService into this EJB
#Resource
private TimerService timer;
private TimerAction action;
#PostConstruct
public void init() {
System.out.println("I will set information to start my task");
// the action object is created before the timer
action = new TimerAction(1);
timer.createTimer(new Date(), PERIOD, "My timer");
}
// this method will be executed when the timer fires - it needs to wrap your `TimerAction` created once per this singleton instance (`TimerAction` does not have to extend `TimerTask` now)
#Timeout
public void runTimerAction() {
action.run();
}
}
TimerTask spawns a new thread whose lifecycle is unaffected by undeploying your application.
A better way to do this would be to use a proper EJB timer with #Schedule like this example:
#Singleton
#Startup
public class SimpleTimerBean {
static Logger logger = Logger.getLogger(SimpleTimerBean.class.getCanonicalName());
#Schedule(hour = "*", minute = "*", second = "*/3", info = "Create user every 3 seconds", timezone = "UTC")
public boolean createUser() {
try {
System.out.println("-------------->" + nbrUsers);
for (int i = 0; i < nbrUsers; i++) {
System.out.println("Create user >>>>" + i);
}
return true;
} catch (Exception e) {
System.out.println("Exception " + e);
return false;
}
}
}
I have the code below:
#Override
public boolean start() {
boolean b = false;
if (status != RUNNING) {
LOGGER.info("Starting Auto Rescheduler Process...");
try {
b = super.start();
final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("Rescheduler-Pool-%d").build();
ExecutorService exServ = Executors.newSingleThreadExecutor(threadFactory);
service = MoreExecutors.listeningDecorator(exServ);
} catch (Exception e) {
LOGGER.error("Error starting Auto Rescheduler Process! {}", e.getMessage());
LOGGER.debug("{}", e);
b = false;
}
} else {
LOGGER.info("Asked to start Auto Rescheduler Process but it had already started. Ignoring...");
}
return b;
}
The AutoRescheduler is the runnable below:
private class AutoScheduler implements Runnable {
private static final String DEFAULT_CONFIGURABLE_MINUTES_VALUE = "other";
private static final long DEFAULT_DELAY_MINUTES = 60L;
#Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
//BLOCKS HERE UNTIL A FINISHED EVENT IS PUT IN QUEUE
final FinishedEvent fEvent = finishedEventsQueue.take();
LOGGER.info("Received a finished Event for {} and I am going to reschedule it", fEvent);
final MyTask task = fEvent.getSource();
final LocalDateTime nextRunTime = caclulcateNextRightTime(task);
boolean b = scheduleEventService.scheduleEventANew(task, nextRunTime);
if (b) {
cronController.loadSchedule();
LOGGER.info("Rescheduled event {} for {}", task, nextRunTime);
}
} catch (InterruptedException e) {
LOGGER.error("Interrupted while waiting for a new finishedEventQueue");
Thread.currentThread().interrupt();
}
}
I see events being caught and put in the queue. Normally I then see them being rescheduled by the AutoReschduler
However from time to time I stop seeing them being rescheduled which leads me to believe that the reschedulingThread dies silently. After this happens no more events are taken from the queue until I restart the process (I have a GUI that allows me to call the stop() and start() methods of the public class). After I restart it though, the blocked events are rescheduled normally which means that they are in the queue indeed.
Does anyone have an idea?
EDIT
I have reproduced the error in Eclipse. The thread does not die (I have tested with the ExecutorService as well. However take() still does not take the item from the queue although it is placed there.