У меня есть приложение Spring Boot, которое из-за странных ограничений должно запускаться каждые три часа и не будет работать с Quartz, поэтому я запускал его каждые три часа из cron ОС, и он закрывается, когда он готов. Однако после добавления micrometer-registry-datadog (и spring-legacy) он никогда не завершает работу, он просто отправляет метрики каждые 20 секунд или независимо от периода по умолчанию, даже после вызова registry.close ().
Обречен ли я, как голландец, вечно плыть по морям обработки, или я совершил очевидную ошибку?
Код: он достигает SpringApplication.exit (ctx), но на самом деле не завершается чисто. (сервис - это TimedExecutorService.)
public void close() throws InterruptedException {
service.shutdown();
service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
meterRegistry.close();
SpringApplication.exit(ctx);
}




Это похоже на ошибку. Возможно, экспортер Datadog работает в не-демоническом потоке. JVM рассматривает потоки, не являющиеся демонами, как критически важную работу для приложения.
По сути, JVM считает, что не следует отключаться, пока не завершится не-демонический поток. В случае с веткой экспортера Datadog этого, вероятно, не произойдет.
Чтобы проверить наличие потоков, не являющихся демонами, используйте jstack для создания дампа потока. (команда: jstack <pid>) или выгрузите все потоки в вашем методе close:
ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
for (ThreadInfo ti : threadMxBean.dumpAllThreads(true, true)) {
System.out.print(ti.toString());
}
Ниже приведен пример вывода дампа потока. Обратите внимание на слово «демон» в первой строке:
"pool-1-thread-1" #13 prio=5 os_prio=31 tid=0x00007fe885aa5000 nid=0xa907 waiting on condition [0x000070000d67b000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000006c07e9720> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Кажется, виновата эта нить. Я ожидал, что экспортер Datadog назовет себя более полезным. Это очищается с помощью метода meterRegistry.close (). Какой тип реестра счетчиков вы закрываете в образце кода?
DatadogMeterRegistry. И я, конечно, вызвал close (), он просто не работает так, как мне хотелось бы.
Включая дамп потока, который я не могу прочитать ... dropbox.com/s/5dwuzeqpmbp1qss/stacktrace.txt?dl=0 Один поток, не являющийся демоном, торчит, пул-1-поток-1, похоже, ожидает блокировки параллелизма, что может быть связано с тем, что я использовал DataDog для его измерения. .. Никогда даже не задумывался об этом аспекте ...