Force JVM to start with different date different than machine time - java

I am using spring boot and #schedule to scheduled some cron jobs to start at specific time ; however , I want to write code to be able to manipulate date and time in my spring boot application in order to test whether the cron job will be triggered or not , I know I can do this through change machine (OS) date , but I want to this through my application startup . I remember I've seen it somewhere , but I couldn't find it again .
#EnableScheduling
#SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
}

You wont be able to change the system time in JVM. You have two options to test.
stack overflow thread to change the system time from Java code. This changes your machine time as well. How can I set the System Time in Java?
stack overflow thread to test the schedule annotation How to test Spring #Scheduled

You can change the timezone of the application by using System.setProperty() method. Below is the example.
System.setProperty("user.timezone", "Asia/Kolkata");

Related

What is the best way to run some method only on FIRST startup of Spring application?

I need to run some methods only once, when application starts for the first time. Is there any basic way to do this in Spring java/kotlin?
UPD:
For the first time means that i have new app that should run some methods on startup, but when i restart this app, i don't want it to run this method again
I would suggest that you use the ApplicationReadyEvent. According to the documentation, the ApplicationReadyEvent is an:
Event published as late as conceivably possible to indicate that the application is ready to service requests.
So, you could implement your own ApplicationListener listening for the ApplicationReadyEvent and run your code only when the application is ready, for example:
#Component
#Order(0)
class CustomApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// run your code
}
}
You can annotate your method with #PostConstruct (make sure you've made spring bean).
At the beginning of that method you can check if file "dummy.txt" exists in project directory if not proceed with method. At the end create file "dummy.txt".
You can also add property while starting java process first time like this:
java -DfirstTime=true -jar myjar.jar
Make firstTime false by default

Parallelization of a scheduled task implemented as #Singleton in a clustered Java EE application

I am currently developing a Java EE application which will be deployed on a Payara server 4. The payara server works on host 1 and there are also 2 instances (host 1 and host 2) available as a Payara cluster.
The problem which I have is, if we schedule a task in the singleton class, then the task will be executed thrice at the same time. The question is 2-fold.
Why does this phenomenon happen?
How can I avoid such multiple execution?
The entry point looks like this. (Not the whole.)
#ApplicationScoped
#Singleton
public class StartClass {
public void StartClass() {}
public void init(#Observes #Initialized(ApplicationScoped.class) ServletContext) throws ... { ... }
#Schedule(hour="*", minute="0", persistent=false)
public void runJob() {
MyClass my_class = new MyClass();
my_class.do_the_job();
}
}
Here the scheduled task which I mentioned above is my_class.do_the_job(). This method is just to insert a line into a DB and the source code is very similar to this tutorial and has several System.out.println("DO_THE_JOB"). The target table has a column which is automatically filled with the inserted timestamp. I also put an information about the host with System.getenv("HOST"). And the result is that we insert three rows every hour: 2 rows from host 1 and 1 row from host 2. But the result of println() can be found once in the log file.
Notes:
Usage of JTA is not the point. I would like to understand the behaviour of the application and the cluster.
Java version is 8
If there should be another relevant part, let me know.
In the JEE spec there is no way to have a #Singleton which is cluster-wide.
One possible option to get around this is to use the Payara-specific clustered singleton with the additional #Clustered annotation. It is available starting from Payara 4.182.
Read more about it here Payara clustered singleton
Why does this phenomenon happen?
Simply because Singleton beans are not clusterable. Meaning that each node of the cluster has its own instance of StartClass. You may find additional useful information on a similar SO question.
How can I avoid such multiple execution?
With your current setup, you can't. What you possibly need is a scheduler which supports clustering. A popular option is quartz-scheduler which supports clustering.

#scheduled annotation with variable fixeddelay

I have a method which is scheduled to run after every 20 minutes. I simply used #Scheduled annotation in Spring boot , However I need a scheduler which takes delay time at runtime. E.g. If I want to be able to change the delay time/frequency of method execution at runtime without stopping the application i.e. change the frequency in DB and Code should adapt it.
#Scheduled(initialDelay=15*60*1000, fixedRate=20*60*1000)
public void MyMethod() {
// Code to repeat after every 20 minutes
}
}
The fixed rate in the code should be variable and taken at the runtime. Is it possible to achieve it ?
You can do it with refresh the spring context after change the fixed rate in the properties file, or using spring cloud config, but this will raise some issues - refresh() should destroy all beans currently living in the context (singletons etc) and recreate them, so any bootstrapping that might happen will happen again.
Here is an reference:
Is spring application context reloading via ConfigurableApplicationContext refresh() considered bad-practice

Spring Shell - usage and execution

I want to integrate Spring Shell within a spring boot application. I am able to execute the examples from the official git-repo. But when migrating the example code to my own project that is very very similar to this code, my individual shell is not shown or usable. Instead the default Spring Shell splash is shown is usable:
<SpringShell ASCII-Art>
1.1.0.RELEASE
Welcome to Spring Shell. For assistance press or type "hint" then hit ENTER
spring-shell>
Compilation gives no errors, but the individual sample #component marked classes are not used. All annotations are properly set. A standard loader outside is existent. I am not executing the code in an IDE.
Although the documentation (chapter 3.5) tells, that the components are automatically collected as far as i understood.
So my question is more or less how to setup the usage better than
this:
public class Main {
public static void main(String[] args) throws Exception {
Bootstrap.main(args);
}
}
And to defeat the default splash!
That comment in the documentation is a bit misleading (I'll change it).
For your components to be picked up, they need to be on the classpath AND you'll need to scan for them somehow.
See for example how in the Spring XD project, there is a scan for the org.springframework.xd.shell package. You need to do something similar for your own package.
SOLUTION:
ebottard's answer brought me to the point of creating a "spring-shell-plugin.xml" under resources\META-INF\spring\... Although the component scan was set externally already, this seems to be necessary. The following code shows how to start it up within an Spring Boot Application where CommandLineRunner is implemented. This should bridge starting problems.
#Component
public class CLIBean implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
Bootstrap bootstrap = new Bootstrap();
bootstrap.run();
}
}

How to launch a Spring Batch job after startup?

How can I run a job configured using Spring-Batch right after application startup?
Currently I'm specifying an exact time using cron job, but that requires to change the cron every time I restart the application:
#JobRegistry, #Joblauncher and a Job.
I execute the job as follows:
#Scheduled(cron = "${my.cron}")
public void launch() {
launcher.run(job, params);
}
Checking aroud Spring code I have found SmartLifecycle
An extension of the Lifecycle interface for those objects that require
to be started upon ApplicationContext refresh and/or shutdown in a
particular order. The isAutoStartup() return value indicates whether
this object should be started at the time of a context refresh.
Try creating a custom bean implementing SmartLifecycle and setting autoStartup; when this custom bean start method is invoked launch your job.
A few options that I can think of on the places to put your startup logic:
.1. In a bean #PostConstruct annotated method, reference is here - http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-postconstruct-and-predestroy-annotations
.2. By implementing an ApplicationListener, specifically for either ContextStartedEvent or ContextRefreshedEvent. Reference here - http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#context-functionality-events

Categories

Resources