Quarkus prometheus percentiles still zeroed after long metrics update time - quarkus

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);
}

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

Unity - TextMeshPro text object doesn't update

I have been using TMP objects in several instances in my game, but all of a sudden it decides not to work on a certain object.
public class BeforeRoundTimer : MonoBehaviour
{
public TextMeshProUGUI timer;
private Timer oneSecondTimer;
private int time = 5;
public void StartCountdown()
{
Debug.Log("One second timer");
oneSecondTimer = new Timer(1000);
oneSecondTimer.Elapsed += UpdateTime;
oneSecondTimer.Enabled = true;
oneSecondTimer.AutoReset = true;
oneSecondTimer.Start();
}
private void UpdateTime(object source, ElapsedEventArgs e)
{
if(time == 0)
{
oneSecondTimer.Stop();
return;
}
timer.text = $"{time}";
time--;
}
}
I know the text is updating because I put debug statements (I have since removed them) and they fired when UpdateTime() is called. I also viewed the inspector when the game was playing, and the text value would update in front of my eyes. The text only changes when I make some stylistic change to it (i.e. making it bold, changing the font asset, including changing the text itself). I have looked back to my old code and it basically runs the exact same way, but it actually changes in game.
Ok so after taking a break, I decided to find another way to call my method every second. Instead of using a Timer, I decided to use Unity's InvokeRepeating() function.
public class BeforeRoundTimer : MonoBehaviour
{
public TextMeshProUGUI timer;
private int count = 0;
public void StartCountdown()
{
InvokeRepeating(nameof(UpdateTime), 0, 1f);
}
private void UpdateTime()
{
if(count == 5)
{
CancelInvoke("UpdateTime");
return;
}
Debug.Log("Update Time");
timer.text = $"{5 - count}";
count++;
}
}
One thing I noticed when trying to use the Timer in a different way is that it was only updating the text value every other second. It ran 10 times (I put a Debug.Log() in UpdateTime()) but only changed the value every other time while not actually updating the TMP. You could replace nameof(UpdateTime) with "UpdateTime", but Visual Studio recommended that I use the former so I went with that.
In short: don't use timers, use Unity's InvokeRepeating() function because it works perfectly. It is actually very similar to JavaScript's setInterval() which I found interesting.

Spring boot with dynamically change cron expression in #Scheduler

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
}

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).

PGM Receive very slow causing messages to be dropped?

I'm looking into ZeroMQ for its PGM support.
Running on Windows (in a VirtualBox with MacOS as host, if that could matter), using the NetMQ library.
The test I want to do is very simple: send messages from A to B as fast as possible...
First I used TCP as transport; this got easily to >150 000 messages per second, with two receivers keeping pace.
Then I wanted to test PGM; all I did was to replace the address "tcp://*:5556" with "pgm://239.0.0.1:5557" on both sides.
Now, the PGM tests give very strange results: the sender easily gets to >200 000 messages/s; the receiver though, manages to process only about 500 messages/s !?
So, I don't understand what is happening.
After slowing down the sender (sleep 10ms after each message, since otherwise it's practically impossible to investigate the flow) it appears to me that the receiver is trying to keep up, initially sees every message passing by, then chokes, misses a range of messages, then tries to keep up again...
I played with the HWM and Recovery Interval settings, but that didn't seem to make much difference (?!).
Can anyone explain what's going on?
Many thanks,
Frederik
Note: Not sure if it's matters: as far as I understand, I don't use OpenPGM - I just download the ZeroMQ setup, and enabled 'Multicasting Support' in Windows.
This is the Sender code:
class MassSender
{
private const string TOPIC_PREFIX = "Hello:";
private static int messageCounter = 0;
private static int timerCounter = 0;
public static void Main(string[] args)
{
Timer timer = new Timer(1000);
timer.Elapsed += timer_Elapsed;
SendMessages_0MQ_NetMQ(timer);
}
private static void SendMessages_0MQ_NetMQ(Timer timer)
{
using (NetMQContext context = NetMQContext.Create())
{
using (NetMQSocket publisher = context.CreateSocket(ZmqSocketType.Pub))
{
//publisher.Bind("tcp://*:5556");
publisher.Bind("pgm://239.0.0.1:5557"); // IP of interface is not specified so use default interface.
timer.Start();
while (true)
{
string message = GetMessage();
byte[] body = Encoding.UTF8.GetBytes(message);
publisher.Send(body);
}
}
}
}
private static string GetMessage()
{
return TOPIC_PREFIX + "Message " + (++messageCounter).ToString();
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Console.WriteLine("=== SENT {0} MESSAGES SO FAR - TOTAL AVERAGE IS {1}/s ===", messageCounter, messageCounter / ++timerCounter);
}
}
and the Receiver:
class MassReceiver
{
private const string TOPIC_PREFIX = "Hello:";
private static int messageCounter = 0;
private static int timerCounter = 0;
private static string lastMessage = String.Empty;
static void Main(string[] args)
{
// Assume that sender and receiver are started simultaneously.
Timer timer = new Timer(1000);
timer.Elapsed += timer_Elapsed;
ReceiveMessages_0MQ_NetMQ(timer);
}
private static void ReceiveMessages_0MQ_NetMQ(Timer timer)
{
using (NetMQContext context = NetMQContext.Create())
{
using (NetMQSocket subscriber = context.CreateSocket(ZmqSocketType.Sub))
{
subscriber.Subscribe(""); // Subscribe to everything
//subscriber.Connect("tcp://localhost:5556");
subscriber.Connect("pgm://239.0.0.1:5557"); // IP of interface is not specified so use default interface.
timer.Start();
while (true)
{
messageCounter++;
byte[] body = subscriber.Receive();
string message = Encoding.UTF8.GetString(body);
lastMessage = message; // Only show message when timer elapses, otherwise throughput drops dramatically.
}
}
}
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Console.WriteLine("=== RECEIVED {0} MESSAGES SO FAR - TOTAL AVERAGE IS {1}/s === (Last: {2})", messageCounter, messageCounter / ++timerCounter, lastMessage);
}
}
What is the size of each message?
You are not using OpenPGM, you are using what is called ms-pgm (Microsoft implementation of PGM).
Anyway you might have to change the MulticastRate of the socket (it defaults to 100kbit/s).
Also what kind of network are you using?
I run into the same issue, the sender can send thousands of messages per second. But my receiver can only receive two hundred messages per second.
I think it could be sending or receiving rate is limited. I check
ZMQ_RATE: Set multicast data rate in http://api.zeromq.org/3-0:zmq-setsockopt
The default rate is just 100kb/s.
When I increase it to 1Gb/s, everything is OK now.
const int rate = 1000000; // 1Gb TX- and RX- rate
m_socket.setsockopt(ZMQ_RATE, &rate, sizeof(rate));

Resources