Schedule a task to run only once - java

I'm working on a recovery monitor which waits for 5 minutes and fires an alert if system has not been recovered yet. The monitor needs to be started at start up and to fire alert only once. The source code looks like this:
#Stateless
public class RecoveryMonitor {
#Inject TimerService timerService;
#Inject MyAlertService alertService;
#Inject SystemRecovery systemRecovery;
public void scheduleMonitor() {
timerService.createSingleActionTimer(TimeUnit.MINUTES.toMillis(5),
new TimerConfig);
}
#Timeout
public void timeout() {
if (!systemRecovery.isDone) {
alertService.alert("System recovery failed");
}
}
}
So, the problem here is how to schedule a task, i.e. invoke scheduleMonitor method. I cannot use #PostConstruct as it's not allowed to. I think about using #Schedule, but it executes a method periodically while I only to do it once. Any solutions and/or suggestions are welcome. Thanks.
L
UPDATE: by making the class not Stateless anymore, e.g. make it a #Singleton, I am able to start scheduling using #PostConstruct. This is not a complete solution but it works for me:
#Singleton
public class RecoveryMonitor {
#Inject TimerService timerService;
#Inject MyAlertService alertService;
#Inject SystemRecovery systemRecovery;
#PostConstruct
public void scheduleMonitor() {
timerService.createSingleActionTimer(TimeUnit.MINUTES.toMillis(5),
new TimerConfig);
}
#Timeout
public void timeout() {
if (!systemRecovery.isDone) {
alertService.alert("System recovery failed");
}
}
}

If you have a Servlet Environment you could fire a CDI Event(e.g. ApplicationStartedEvent) within a ServletContextListener and observe that event in your EJB. This kind of startup logic has to be done manually in CDI 1.0. Future versions will probably contain something similar.
If you have questions on how to do that, just ask :)

Related

Spring boot - task on startup preventing application interface exposure

Is it possible to somehow in Spring boot application achieve some startup procedure that blocks every exposure of endpoints (and possibly other application public interfaces) until the startup procedure is completed?
I mean something like
#Component
public class MyBlockingStartupRunner implements ApplicationRunner {
#Override
public void run(ApplicationArguments args) {
// doing some task, calling external API, processing return values, ...
startTask();
// at this point app should be available for rest calls, scheduled tasks etc.
someObject.appIsReadyToGo(); // alternatively app would be ready at the end of the method
}
}
Problem with this approach of using ApplicationRunner is there might be some API calls to the server that I am unable to serve and therefore I would need to add some check at every API endpoint to prevent this. Or, alternatively, create some interceptor that would "block" all public communication and which would probably read some property from some service which tells it if app is ready or not. But thats not the approach I would like and I wonder if Spring implemented this somehow.
If it is acceptable to run your start-up tasks before the web server instance has started at all, you could use SmartLifecycle to add a start task.
#Component
class MyStartup implements SmartLifecycle {
private final ServletWebServerApplicationContext ctx;
private final Log logger = LogFactory.getLog(MyStartup.class);
#Autowired
MyStartup(ServletWebServerApplicationContext ctx) {
this.ctx = ctx;
}
#Override
public void start() {
logger.info("doing start stuff: " + ctx.getWebServer());
startTask();
}
#Override
public void stop() {}
#Override
public boolean isRunning() {
return false;
}
#Override
public int getPhase() {
return 100;
}
}
Because the task runs before the web server has started (rather than blocking access) this might be a different approach.

Using ConfigProperty in manually instantiated classes in JakartaEE / Helidon / Microprofile

I have a small application in Helidon start. It is mostly a REST interface, but I also want to start some background monitoring / logging on startup.
I would like that monitoring to be activated / deactivated by config.
The issue I am facing is that the config is not being picked up if my class is instantiated manually.
Here is a very short code snippet :
Starting the application
public class Main {
private Main() { }
public static void main(final String[] args) throws IOException {
Server server = startServer();
CellarMonitoring monitoring = new CellarMonitoring();
monitoring.start();
}
static Server startServer() {
return Server.create().start();
}
}
Starting monitoring or not based on Configuration :
package nl.lengrand.cellar;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
public class CellarMonitoring {
#Inject
#ConfigProperty(name = "monitoring.enabled", defaultValue = "true")
private volatile boolean monitoringEnabled; <= Always false
public void start(){
if(monitoringEnabled) {
System.out.println("Monitoring enabled by config. Starting up");
}
else System.out.println("Monitoring disabled by config");
}
}
This code will always return "Monitoring disabled by config", whatever I do.
Accessing the config directly like described in the documentation is not really an option either since the onStartup method will never be fired.
What is the proper way to inject a class in my server so it can access the config as desired?
Your question is actually about CDI.
In order for any kind of dependency injection to work with CDI, CDI must instantiate the thing to be injected. In this case, you instantiate the thing to be injected, so CDI never "sees" it, so it is never injected.
I am speculating here, but I'm guessing your use case is really just: "I'd like my CellarMonitoring component to be notified when CDI comes up. How do I do that?"
There are many answers to that question on this site and elsewhere. Essentially you take advantage of the fact that CDI will fire an event notifying any interested listeners in the initialization of the application scope. The application scope is effectively the lifespan of the application itself, so you can think of it as a startup event.
A full CDI tutorial is beyond the scope of this question and answer, but, to cut to the chase, here's a way to do it. I have had to make various assumptions, such as that you want CellarMonitoring to be singleton-like:
#ApplicationScoped
public class CellarMonitoring {
#Inject
#ConfigProperty(name = "monitoring.enabled", defaultValue = "true")
private volatile boolean monitoringEnabled; // <= Always false
public void start() {
if (monitoringEnabled) {
System.out.println("Monitoring enabled by config. Starting up");
} else {
System.out.println("Monitoring disabled by config");
}
}
private void onStartup(#Observes #Initialized(ApplicationScoped.class) final Object event) {
// The container has started. You can now do what you want to do.
this.start();
}
}

How do I use JpaRepository in a backend thread?

I have an interface as follows:
public interface PackageRepository extends JpaRepository<DocPackage, String> {
}
Now I'm able to use this without any problem from my REST services by using:
#Resource
PackageRepository repo;
I can make transactional calls on it with no problem.
However when I try to load this from a worker thread:
public class MyWorker implements Runnable {
#Resource
PackageRepository repo;
#Transactional
private void doSomething() {
DocPackage pck = repo.findOne("key");
pck.setStatus(2);
repo.saveAndFlush(pck);
}
public void run() {
//stuff
doSomething();
//other stuff
}
}
new Thread(new MyWorker()).start();
I'm able to do reads on this repo just fine, but whenever I save and flush I get the exception:
javax.persistence.TransactionRequiredException: no transaction is in progress
Is there any way to get this done correctly?
Spring, by default, use proxies. This mean #Transaction works only when method called from outside of class.
To fix it extract you method to service. Inject your service in MyWorker and call it.
I think you need to add the #Transactional annotation to your method

scheduledExecutorService, timerService and Stateless EJB on scheduled jobs

I'm trying to implement a system in server that will do some updates on database on a ragular basis.
Here: Spawning threads in a JSF managed bean for scheduled tasks using a timer
and in some other similar questions, I saw that BalusC strongly recommended to use Stateless Beans, if not possible SchedulerExecuterService rather than Timer.
Here is my situation. I need a JSF page in which I can configure the schedule interval. i.e. I can change its rule from run once in every 5 min to run once in 10 min
First, I tried to use #Schedule annotation and it was great. However, I couldn't find a way to change interval with that. First question, is it possible to change it dynamically like I told above?
I am currently using SchedulerExecutorService which is called from #PostConstruct of a Stateless Bean.
Second question, is the Timer BalusC strongly recommended not to use is the TimerService of EJB?
Third Question, I liked the properties of timerService which is:
using scheduleExpression and timerConfig.
Are there any similar things for ScheduledExecutorService?
Additional Question: Am I on right track? Can the thing that I am trying to pull be done in a better way?
I think #Schedule is used only for fixed cron-like timers, where the EJB container deploys a timer at EJB startup. You obviously need more dynamic scheduling connected with a JSF page.
If you are running on a full Java EE 6 profile, why not use the TimerService with a Stateless Session EJB like this:
#Stateless
public class JobSchedulerBean {
#Resource
private TimerService timerService;
// #PostConstruct
public void initTimer() {
// set initial timer
ScheduleExpression sch = new ScheduleExpression();
// set cron expression into sch
timerService.createCalendarTimer(sch, new TimerConfig("myTimer", false));
}
public void rescheduleTimer(int interval) {
// get timer from timer service
for (Timer timer : timerService.getTimers()) {
if (timer != null && timer.getInfo().equals("myTimer")) {
timer.cancel();
}
}
// schedule new timer, like in initTimer() method
}
#Timeout
public void timeout(Timer timer) {
// do the job
}
}
EDIT:
#ManagedBean(eager=true)
#ApplicationScoped
public class JobRunner {
private ScheduledExecutorService scheduler;
private static final int POOL_SIZE = 1;
ScheduledFuture<?> runHandle;
#PostConstruct
public void init() {
scheduler = Executors.newScheduledThreadPool(POOL_SIZE);
// set initial expiry to 5 minutes after 5 minutes delay
runHandle = scheduler.scheduleAtFixedRate(new MyJob(), 5, 5, TimeUnit.MINUTES);
}
#PreDestroy
public void destroy() {
scheduler.shutdownNow();
}
public void reschedule(int newDelay) {
// cancel old timer, but do not interrupt it
runHandle.cancel(false);
runHandle = scheduler.scheduleAtFixedRate(new MyJob(), newDelay, newDelay, TimeUnit.MINUTES);
}
}
public class MyJob implements Runnable {
public void run() {
// do the job
}
}

I need a thread in Web/JavaEE container to complete AsyncContext objs in same JVM

I need a thread in Web/JavaEE container to fetch information from an external source and complete corresponding AsyncContext objs in same JVM.
I wish to have a zero-added-latency solution, so periodic polling or a timer is ruled out.
I could start a thread but I believe it is frowned upon in a Web container and not portable. Q1. Is it possible to run a thread portably in a Java EE container instead?
Q2. If I want to run a thread in a Web Container anyway, what is the "least of all evil" ways? InitializeContext? ExecutorService? Thread.run?
Thanks!
AsyncContext.html#start is probably the closest you can get.
You can use work manager in jsr237 for creating a thread in a Java EE container. : http://jcp.org/en/jsr/detail?id=237. If you want an asynchronous job, you should use JMS.
In Java EE 6, you can put the #Asynchronous annotation on an EJB method to have the work in that method be handled by a special thread-pool:
#Stateless
public class SomeBean {
#Asynchronous
public void doSomething() {
// ...
}
}
Then somewhere else, inject this bean and call the doSomething() method. Control will return immediately.
#WebServlet("/test")
public class SyncServlet extends HttpServlet {
#EJB
private SomeBean someBean;
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
someBean.doSomething();
}
}
Note that you might not need something like AsyncContext asyncContext = request.startAsync() here. You would use this only if the asynchronous code would still need to send something to the response.
If you need something akin to a period timer though, and not do something in response to a request, you can use the timer service in a singleton:
#Startup
#Singleton
public class SomeTimerBean {
#Schedule(hour = "*", minute = "*/30", second = "0", persistent = false)
public void doStuff() {
// ...
}
}
Instead of running periodically, you can also run something like this once using the #TimeOut annotation:
#Startup
#Singleton
public class SomeTimerBean {
#Resource
private TimerService timerService;
#Postconstruct
public void init() {
timerService.createSingleActionTimer(0, new TimerConfig(null, false));
}
#Timeout
public void doStuff(Timer timer) {
// ...
}
}
You can have variants on this, e.g. SomeTimerBean can also call an #Asynchronous method in an other bean as well to basically have the same effect.

Categories

Resources