Spring boot with dynamically change cron expression in #Scheduler - spring-boot

I'M trying to run my app by implementing scheduler with cron expression. To run my application I have three conditions:-
First condition is :
I have some time slots like
LocalTime [] slots = {LocalTime.of(0, 0), LocalTime.of(7, 0), LocalTime.of(13, 0), LocalTime.of(19, 0)}
Now the condition is when JVM start it will first check the time duration from current time and the given time slot. Below is the method to check the duration:-
public static Duration findNextSlotDuration(LocalTime now, LocalTime [] slots) {
Duration duration = null;
if(slots != null)
{
if(slots.length == 1)
{
duration = Duration.between(now, slots[0]);
}else if(slots.length > 1)
{
for (int i = 0; i < slots.length-1; i++) {
if(isBetween(now, slots[i], slots[i+1]))
{
duration = Duration.between(now, slots[i+1]);
break;
}
}
}
if(duration != null && !duration.isNegative())
return duration;
else
{
Duration d1 = Duration.between(now, LocalTime.of(23, 59)).plusMinutes(1);
Duration d2 = Duration.between(LocalTime.of(0, 0), slots[0]);
return d1.plus(d2);
}
}
return Duration.ofMinutes(5);
}
private static boolean isBetween(LocalTime candidate, LocalTime start, LocalTime end) {
return !candidate.isBefore(start) && !candidate.isAfter(end); // Inclusive.
}
For example if JVM start at 17PM today then it will first check the time slot and it will get slot between 13 to 19 PM and duration will be 2 hours as per method findNextSlotDuration , so the scheduler will start after 2 hour means at 19 PM. Another scenario, if JVM start today at 19 Hr 00 Min 29 Sec then it will not get the slot so, the duration will be 6 Hr 00 Min 29 Sec then the scheduler start at 00:00:29 O'Clock.
Now the second condition is:
If the JVM is still running after completing my task then it will again run my task after every 6 hours.
The Last condition is:
It will run only from Monday to Saturday
So any idea how I can implement #Scheduler with Cron or any better approach in Spring boot.

Firstly, I will try to give some suggestions to you if I understand correctly. I hope it will be helpful for you
You can catch application ready event as below and also you can implement whenever you want to perform. Also you can trigger your method by using this approach.
#Component
public class AppReadyComponent implements ApplicationListener<ApplicationReadyEvent> {
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// some logic
}
}
Lastly, you can dynamically calculate cron values and use it to trigger your scheduled method as below.
#SpringBootApplication
public class MainApp {
#Bean
public String getCronValue() {
// here you may calculate cron value dynamically and return it as a string
return cronValue;
}
}
Here is your scheduled method
#Scheduled(cron = "#{#getCronValue}")
public void process() {
// some logic
}

Related

Unity Coroutine performances

I used Coroutine in Unity quite a lot in my projects, they are useful because they allow me to delay functions or do things every X seconds.
Now I know how to use them, but I don't really know what is happening in the background and I am wondering their impact on performances. Are coroutine low/fast ?
For exemple, doing things every few seconds could be done in the Update function, but it can also be done in a coroutine with WaitForSeconds or with yield return null. Are they all as efficient as the others ?
I wrote different ways here, which should do the job in theory. But which ones are the best ? If they are all the same, WaitForSeconds seems easier to read and I might prefer it.
Update way
private float shootInterval = 5f;
private float counterDeltaTime = 0f;
private void Update() {
counterDeltaTime += Time.deltaTime;
if (counterDeltaTime >= shootInterval) {
Shoot();
counterDeltaTime = 0;
}
}
Coroutine way
yield return new WaitForSeconds
private void Start() {
StartCoroutine(ShootEvery(5f));
}
private IEnumerator ShootEvery(float seconds) {
yield return new WaitForSeconds(seconds);
Shoot();
StartCoroutine(ShootEvery(seconds));
}
yield return null
private void Start() {
StartCoroutine(ShootEvery(5f));
}
private IEnumerator ShootEvery(float seconds) {
float dt = 0;
while(dt < seconds) {
yield return null;
dt += Time.deltaTime;
}
Shoot();
StartCoroutine(ShootEvery(5f));
}
Thanks for answers

Quarkus prometheus percentiles still zeroed after long metrics update time

I have a service bean MonitoringRegistryServiceImpl implementation in the Quarkus which I used to register timers and update them (code bellow). They were registered only once (into map timerMap) and then reused when recording / updating their values.
The problem I had that if I called http://localhost:8080/q/metrics to see the current state of percentile metrics I saw only zero values.
This happens only after long time period (e.g.3 hours without update of metrics). So far so good, that is something I would expect as there is distributionStatisticExpiry(Duration.ofMinutes(5)) for the percentiles. Let's call it "natural decay of values" :)
However, if I would updated the metrics and then called the http://localhost:8080/q/metrics again the zero values on percentiles were still there yet related counters and max values were updated correctly.
Maybe my understanding of percentiles is not complete, please advice.
Note: I use quarkus-micrometer-registry-prometheus artifact.
#JBossLog
#ApplicationScoped
public class MonitoringRegistryServiceImpl implements MonitoringRegistryService {
private static final double[] PERCENTILES = { 0.5, 0.75, 0.95, 0.99 };
private Map<String, Timer> timerMap = new ConcurrentHashMap<>();
#Inject
MeterRegistry registry;
#Override
public <T> void updateTimer(String timerName, String[] tags,
Duration duration) {
String key = timerName + "_" + String.join(".", tags);
Timer timer = timerMap.get(key);
if (timer != null) {
log.debug("Key found:" + key);
timer.record(duration);
} else {
log.debug("Key not found:" + key);
Timer newTimer = Timer.builder(timerName).tags(newTags).publishPercentiles(PERCENTILES)
.distributionStatisticExpiry(Duration.ofMinutes(5))
.register(registry);
timerMap.put(key, newTimer);
newTimer.record(duration);
}
}
}
The solution was quite simple, rather than using the Timer.builder()..register() just use registry.timer(). There was also no need for the timerMap above. After this change, the timers metrics were not zeroed.
Timer timer = registry.timer(timerName, tags);
if (duration != null) {
timer.record(duration);
} else {
log.error("Time duration was equal to null for a metric with a timerName:" + timerName);
}

rocketmq throw exception "[TIMEOUT_CLEAN_QUEUE]broker busy, start flow control for a while"

version:rocketmq-all-4.1.0-incubating
We send msg 1000 QPS,sync send, but throw exception:-
[TIMEOUT_CLEAN_QUEUE] broker busy, start flow control for a while
There is the related code:
while (true) {
try {
if (!this.brokerController.getSendThreadPoolQueue().isEmpty()) {
final Runnable runnable = this.brokerController.getSendThreadPoolQueue().peek();
if (null == runnable) {
break;
}
final RequestTask rt = castRunnable(runnable);
if (rt == null || rt.isStopRun()) {
break;
}
final long behind = System.currentTimeMillis() - rt.getCreateTimestamp();
if (behind >= this.brokerController.getBrokerConfig().getWaitTimeMillsInSendQueue()) {
if (this.brokerController.getSendThreadPoolQueue().remove(runnable)) {
rt.setStopRun(true);
rt.returnResponse(RemotingSysResponseCode.SYSTEM_BUSY, String.format("[TIMEOUT_CLEAN_QUEUE]broker busy, start flow control for a while, period in queue: %sms, size of queue: %d", behind, this.brokerController.getSendThreadPoolQueue().size()));
}
} else {
break;
}
} else {
break;
}
} catch (Throwable ignored) {
}
}
}
I find broker the default value of sendMessageThreadPoolNums is 1,
/**
* thread numbers for send message thread pool, since spin lock will be used by default since 4.0.x, the default value is 1.
*/
private int sendMessageThreadPoolNums = 1; //16 + Runtime.getRuntime().availableProcessors() * 4;
private int pullMessageThreadPoolNums = 16 + Runtime.getRuntime().availableProcessors() * 2;
but the previous version isn't 1, and if I configure sendMessageThreadPoolNums = 100, can resolve this question ? It will lead to what is different with default value.
thanks
SHORT ANSWER:
you have two choices:
set sendMessageThreadPoolNums to a small number, say 1, which is the default value after version 4.1.x. And, remain the default value of useReentrantLockWhenPutMessage=false, which is introduced after 4.1.x
sendMessageThreadPoolNums=1
useReentrantLockWhenPutMessage=false
If you need to use a large numbers of threads to process sending message, you'd better use useReentrantLockWhenPutMessage=true
sendMessageThreadPoolNums=128//large thread numbers
useReentrantLockWhenPutMessage=true // indicating that do NOT use spin lock but use ReentrantLock when putting message

Testing if random number equals a specific number

I know this might already have been answered, but all the places where i found it, it wouldn't work properly. I'm making a game in Greenfoot and I'm having an issue. So I'm generating a random number every time a counter reaches 600, and then testing if that randomly generated number is equal to 1, and if it is, it creates an object. For some reason, the object will be created every time the counter reaches 600. I'm somewhat new to Java so it's probably something simple.
import greenfoot.*;
import java.util.Random;
/**
* Write a description of class Level_One here.
*
* #CuddlySpartan
*/
public class Level_One extends World
{
Counter counter = new Counter();
/**
* Constructor for objects of class Level_One.
*
*/
public Level_One()
{
super(750, 750, 1);
prepare();
}
public Counter getCounter()
{
return counter;
}
private void prepare()
{
addObject(counter, 150, 40);
Ninad ninad = new Ninad();
addObject(ninad, getWidth()/2, getHeight()/2);
Fail fail = new Fail();
addObject(fail, Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()));
}
private int spawnCounter = 0;
private int invincibleCounter = 0;
Random random = new Random();
private int randomNumber;
public void act()
{
controls();
{if (spawnCounter > 500) {
spawnCounter = 0;
addObject(new Fail(), Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()));
}
spawnCounter++;
{if (spawnCounterTwo > 300) {
spawnCounterTwo = 0;
addObject(new APlus(), Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()));
}
spawnCounterTwo++;
}
if (invincibleCounter > 600)
{
int randomNumber = random.nextInt(10);
if (randomNumber == 1)
{
Invincible invincible = new Invincible();
addObject(invincible, Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()));
invincibleCounter = 0;
}
if (randomNumber == 2)
{
Storm storm = new Storm();
addObject(storm, Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()));
}
else
{
}
}
invincibleCounter ++;
}
}
private int spawnCounterTwo = 100;
public void controls()
{
if (Greenfoot.isKeyDown("escape"))
{
Greenfoot.stop();
}
}
}
I'm not getting errors as it is compiling fine, but when i run it i have issues. Any help? Thanks in advance!
This is only speculation, since I cannot see the rest of your code, but I suspect that you are seeding your random number generator with some constant number. So every time you run your program, the random number generator generates numbers in the same order. In order to confirm this, please show some more code.
Also, your brackets do not match, so at least please show enough code to have matching curly braces.
Are you sure it is created exactly when the counter hits 600? You're incrementing the counter every frame, and at the default ~30 fps speed, that's twenty seconds. Then every frame after that, you're getting a random integer and have a 10% chance to make an Invincible. But 10% chance will on average come up within ten frames, which is 1/3 of a second. Then the counter will reset and you'll wait twenty more seconds, then create an Invincible within the next second, and so on. If you want a 10% chance every 20 seconds, you need to reset the Counter in the else branch, as well as the "then" branch (or just reset it just inside your very first if).

Memory usage in IE for gwt application

For the last couple of days I've been trying to find out why my gwt application is leaking on IE 9.
I want to share one of my findings with you and maybe someone can give me a clue about what is going one here...
I wrote this small test:
public class Memory implements EntryPoint
{
FlowPanel mainPanel = new FlowPanel();
FlowPanel buttonsPanel = new FlowPanel();
FlowPanel contentPanel = new FlowPanel();
Timer timer;
Date startDate;
public void onModuleLoad()
{
mainPanel.setWidth("100%");
mainPanel.setHeight("100%");
RootPanel.get().add(mainPanel);
Button startBtn = new Button("start test");
startBtn.addClickHandler(new ClickHandler(){
#Override
public void onClick(ClickEvent event)
{
startDate = new Date();
System.out.println("Started at " + startDate);
timer = new Timer()
{
public void run()
{
Date now = new Date();
if(isWithin5Minutes(startDate, now))
{
manageContent();
}
else
{
System.out.println("Complete at " + new Date());
timer.cancel();
contentPanel.clear();
}
}
};
timer.scheduleRepeating(50);
}
});
buttonsPanel.add(startBtn);
mainPanel.add(buttonsPanel);
mainPanel.add(contentPanel);
}
private void manageContent()
{
if(contentPanel.getWidgetCount() > 0)
{
contentPanel.clear();
}
else
{
for(int i =0; i < 20; i++)
{
Image image = new Image();
image.setUrl("/images/test.png");
contentPanel.add(image);
}
}
}
private boolean isWithin5Minutes(Date start, Date now)
{
//true if 'now' is within 5 minutes of 'start' date
}
}
So, I have this Timer that runs every 50 ms (during around 5 minutes) and executes the following:
- if the panel has content, clear it;
- if the panel has no content add 20 png images (30x30 with transparency) to it.
Using the Process Explorer from sysInternals I got the following results:
IE 9:
Firefox 21.0:
I ran the same program with some changes (.jpg images instead of .png, create the images only once and use them as member variables, create the images using a ClientBundle) but the result was the same. Also, I ran the application in production mode.
Is there something wrong with my code that could cause this behavior in IE?
Shouldn't the Garbage Collector (GC) free some of the used memory at least when the timer ends?
Any of you came across this problem before?
Garbage collector in IE is quite strange thing. E.g. you can force it to run by simply minimizing browser window. I guess leaks in your case are images that weren't removed properly by browser when you clear container. Try to remove them by using JS "delete" operation, like that:
private native void utilizeElement(Element element) /*-{
delete element;
}-*/;
Then change your manageContent a little:
if(contentPanel.getWidgetCount() > 0)
{
for (Iterator<Widget> it = contentPanel.iterator(); it.hasNext();)
utilizeElement(it.next().getElement());
contentPanel.clear();
}
Hope this helps.

Resources