-
Bug
-
Resolution: Duplicate
-
Major
-
None
-
2.1.9.Final
-
None
MailHandler that ships with AngusMail has thread local deal with reentrant Handler publish calls due to AngusMail using JUL and the MailHandler using AngusMail. Log4j2 and logback have similar guards in-place to deal with feedback loops. In the normal case the guard is never triggered unless log levels get low enough that AugusMail starts issuing debug statements.
Using wildfly-29.0.1.Final, the AsyncHandler with BLOCK overflow policy + MailHandler I'm able to observe that WildFly will never boot because the AsyncHandler has filled its blocking queue and parked the worker thread and all other threads publishing. Because the work thread is parked progress is never made.
Here is jstack output from WildFly showing that main thread and AsyncHandler worker are calling BlockingQueue.put:
2023-09-27 22:08:04 Full thread dump OpenJDK 64-Bit Server VM (17.0.7+7-Ubuntu-0ubuntu118.04 mixed mode, sharing): Threads class SMR info: _java_thread_list=0x0000564b040111e0, length=14, elements={ 0x0000564b033677e0, 0x0000564b03412c20, 0x0000564b03414550, 0x0000564b0341a290, 0x0000564b0341b910, 0x0000564b0341d130, 0x0000564b0341eef0, 0x0000564b03420830, 0x0000564b0347e4a0, 0x0000564b03556f20, 0x0000564b03559700, 0x0000564b035fa640, 0x0000564b04239f10, 0x0000564b05024db0 } "main" #1 prio=5 os_prio=0 cpu=2134.93ms elapsed=36.55s tid=0x0000564b033677e0 nid=0xade waiting on condition [0x00007fbe685d3000] java.lang.Thread.State: WAITING (parking) at jdk.internal.misc.Unsafe.park(java.base@17.0.7/Native Method) - parking to wait for <0x00000000e06307c8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(java.base@17.0.7/LockSupport.java:341) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(java.base@17.0.7/AbstractQueuedSynchronizer.java:506) at java.util.concurrent.ForkJoinPool.unmanagedBlock(java.base@17.0.7/ForkJoinPool.java:3463) at java.util.concurrent.ForkJoinPool.managedBlock(java.base@17.0.7/ForkJoinPool.java:3434) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@17.0.7/AbstractQueuedSynchronizer.java:1623) at java.util.concurrent.ArrayBlockingQueue.put(java.base@17.0.7/ArrayBlockingQueue.java:370) at org.jboss.logmanager.handlers.AsyncHandler.doPublish(AsyncHandler.java:155) at org.jboss.logmanager.ExtHandler.publish(ExtHandler.java:77) at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:333) at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) at org.jboss.logmanager.Logger.logRaw(Logger.java:852) at org.jboss.logmanager.Logger.logRaw(Logger.java:862) at org.jboss.logmanager.Logger.log(Logger.java:395) at org.jboss.modules.log.JDKModuleLogger.doLog(JDKModuleLogger.java:102) at org.jboss.modules.log.JDKModuleLogger.moduleDefined(JDKModuleLogger.java:181) at org.jboss.modules.ModuleLoader$3.run(ModuleLoader.java:736) at org.jboss.modules.ModuleLoader$3.run(ModuleLoader.java:728) at java.security.AccessController.executePrivileged(java.base@17.0.7/AccessController.java:807) at java.security.AccessController.doPrivileged(java.base@17.0.7/AccessController.java:569) at org.jboss.modules.ModuleLoader.defineModule(ModuleLoader.java:728) at org.jboss.modules.ModuleLoader.loadModuleLocal(ModuleLoader.java:535) at org.jboss.modules.DelegatingModuleLoader.preloadModule(DelegatingModuleLoader.java:57) at org.jboss.modules.Module.addPaths(Module.java:1257) at org.jboss.modules.Module.link(Module.java:1627) at org.jboss.modules.Module.getPaths(Module.java:1588) at org.jboss.modules.Module.getPathsUnchecked(Module.java:1611) at org.jboss.modules.Module.loadModuleClass(Module.java:760) at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:192) at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410) at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398) at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116) at java.lang.ClassLoader.defineClass1(java.base@17.0.7/Native Method) at java.lang.ClassLoader.defineClass(java.base@17.0.7/ClassLoader.java:1012) at org.jboss.modules.ModuleClassLoader.doDefineOrLoadClass(ModuleClassLoader.java:350) at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:482) at org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:276) at org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:79) at org.jboss.modules.Module.loadModuleClass(Module.java:765) at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:192) at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410) at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398) at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116) at java.lang.ClassLoader.defineClass1(java.base@17.0.7/Native Method) at java.lang.ClassLoader.defineClass(java.base@17.0.7/ClassLoader.java:1012) at org.jboss.modules.ModuleClassLoader.doDefineOrLoadClass(ModuleClassLoader.java:350) at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:482) at org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:276) at org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:79) at org.jboss.modules.Module.loadModuleClass(Module.java:765) at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:192) at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410) at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398) at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116) at org.jboss.as.jmx.PluggableMBeanServerBuilder.newMBeanServer(PluggableMBeanServerBuilder.java:49) at javax.management.MBeanServerFactory.newMBeanServer(java.management@17.0.7/MBeanServerFactory.java:329) - locked <0x00000000e1e0b580> (a org.jboss.as.jmx.PluggableMBeanServerBuilder) at javax.management.MBeanServerFactory.createMBeanServer(java.management@17.0.7/MBeanServerFactory.java:231) at javax.management.MBeanServerFactory.createMBeanServer(java.management@17.0.7/MBeanServerFactory.java:192) at java.lang.management.ManagementFactory.getPlatformMBeanServer(java.management@17.0.7/ManagementFactory.java:484) - locked <0x00000000e06ea1b0> (a java.lang.Class for java.lang.management.ManagementFactory) at org.jboss.modules.Main.main(Main.java:545) "Reference Handler" #2 daemon prio=10 os_prio=0 cpu=1.73ms elapsed=36.52s tid=0x0000564b03412c20 nid=0xae5 waiting on condition [0x00007fbe4921b000] java.lang.Thread.State: RUNNABLE at java.lang.ref.Reference.waitForReferencePendingList(java.base@17.0.7/Native Method) at java.lang.ref.Reference.processPendingReferences(java.base@17.0.7/Reference.java:253) at java.lang.ref.Reference$ReferenceHandler.run(java.base@17.0.7/Reference.java:215) "Finalizer" #3 daemon prio=8 os_prio=0 cpu=1.26ms elapsed=36.52s tid=0x0000564b03414550 nid=0xae6 in Object.wait() [0x00007fbe4911a000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(java.base@17.0.7/Native Method) - waiting on <0x00000000e013bfe8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(java.base@17.0.7/ReferenceQueue.java:155) - locked <0x00000000e013bfe8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(java.base@17.0.7/ReferenceQueue.java:176) at java.lang.ref.Finalizer$FinalizerThread.run(java.base@17.0.7/Finalizer.java:172) "Signal Dispatcher" #4 daemon prio=9 os_prio=0 cpu=1.17ms elapsed=36.51s tid=0x0000564b0341a290 nid=0xae7 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Service Thread" #5 daemon prio=9 os_prio=0 cpu=1.18ms elapsed=36.51s tid=0x0000564b0341b910 nid=0xae8 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Monitor Deflation Thread" #6 daemon prio=9 os_prio=0 cpu=3.57ms elapsed=36.51s tid=0x0000564b0341d130 nid=0xae9 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread0" #7 daemon prio=9 os_prio=0 cpu=3316.31ms elapsed=36.51s tid=0x0000564b0341eef0 nid=0xaea waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE No compile task "C1 CompilerThread0" #10 daemon prio=9 os_prio=0 cpu=1703.23ms elapsed=36.51s tid=0x0000564b03420830 nid=0xaeb waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE No compile task "Sweeper thread" #11 daemon prio=9 os_prio=0 cpu=0.68ms elapsed=36.51s tid=0x0000564b0347e4a0 nid=0xaec runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Common-Cleaner" #12 daemon prio=8 os_prio=0 cpu=1.25ms elapsed=36.46s tid=0x0000564b03556f20 nid=0xaed in Object.wait() [0x00007fbe4471a000] java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait(java.base@17.0.7/Native Method) - waiting on <0x00000000e013c1f8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(java.base@17.0.7/ReferenceQueue.java:155) - locked <0x00000000e013c1f8> (a java.lang.ref.ReferenceQueue$Lock) at jdk.internal.ref.CleanerImpl.run(java.base@17.0.7/CleanerImpl.java:140) at java.lang.Thread.run(java.base@17.0.7/Thread.java:833) at jdk.internal.misc.InnocuousThread.run(java.base@17.0.7/InnocuousThread.java:162) "Notification Thread" #13 daemon prio=9 os_prio=0 cpu=0.29ms elapsed=36.45s tid=0x0000564b03559700 nid=0xaee runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Reference Reaper" #14 daemon prio=5 os_prio=0 cpu=0.43ms elapsed=36.19s tid=0x0000564b035fa640 nid=0xaf0 in Object.wait() [0x00007fbe43de6000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(java.base@17.0.7/Native Method) - waiting on <0x00000000e013c3b0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(java.base@17.0.7/ReferenceQueue.java:155) - locked <0x00000000e013c3b0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(java.base@17.0.7/ReferenceQueue.java:176) at org.jboss.modules.ref.References$ReaperThread.run(References.java:64) "pool-1-thread-1" #16 daemon prio=5 os_prio=0 cpu=2218.46ms elapsed=32.32s tid=0x0000564b04239f10 nid=0xaf2 waiting on condition [0x00007fbe43ce4000] java.lang.Thread.State: WAITING (parking) at jdk.internal.misc.Unsafe.park(java.base@17.0.7/Native Method) - parking to wait for <0x00000000e06307c8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(java.base@17.0.7/LockSupport.java:341) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(java.base@17.0.7/AbstractQueuedSynchronizer.java:506) at java.util.concurrent.ForkJoinPool.unmanagedBlock(java.base@17.0.7/ForkJoinPool.java:3463) at java.util.concurrent.ForkJoinPool.managedBlock(java.base@17.0.7/ForkJoinPool.java:3434) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@17.0.7/AbstractQueuedSynchronizer.java:1623) at java.util.concurrent.ArrayBlockingQueue.put(java.base@17.0.7/ArrayBlockingQueue.java:370) at org.jboss.logmanager.handlers.AsyncHandler.doPublish(AsyncHandler.java:155) at org.jboss.logmanager.ExtHandler.publish(ExtHandler.java:77) at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:333) at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) at org.jboss.logmanager.Logger.logRaw(Logger.java:852) at org.jboss.logmanager.Logger.logp(Logger.java:659) at org.eclipse.angus.mail.util.MailLogger.log(MailLogger.java:218) at org.eclipse.angus.mail.util.LogOutputStream.log(LogOutputStream.java:105) at org.eclipse.angus.mail.util.LogOutputStream.logBuf(LogOutputStream.java:114) at org.eclipse.angus.mail.util.LogOutputStream.write(LogOutputStream.java:78) at org.eclipse.angus.mail.util.TraceOutputStream.write(TraceOutputStream.java:118) at java.io.BufferedOutputStream.flushBuffer(java.base@17.0.7/BufferedOutputStream.java:81) at java.io.BufferedOutputStream.write(java.base@17.0.7/BufferedOutputStream.java:95) - locked <0x00000000e1e30d90> (a java.io.BufferedOutputStream) at org.eclipse.angus.mail.util.CRLFOutputStream.write(CRLFOutputStream.java:47) at org.eclipse.angus.mail.smtp.SMTPOutputStream.write(SMTPOutputStream.java:46) at org.eclipse.angus.mail.util.QPEncoderStream.output(QPEncoderStream.java:188) at org.eclipse.angus.mail.util.QPEncoderStream.write(QPEncoderStream.java:125) at java.io.FilterOutputStream.write(java.base@17.0.7/FilterOutputStream.java:87) at java.io.FilterOutputStream.write(java.base@17.0.7/FilterOutputStream.java:137) at sun.nio.cs.StreamEncoder.writeBytes(java.base@17.0.7/StreamEncoder.java:234) at sun.nio.cs.StreamEncoder.implWrite(java.base@17.0.7/StreamEncoder.java:304) at sun.nio.cs.StreamEncoder.implWrite(java.base@17.0.7/StreamEncoder.java:282) at sun.nio.cs.StreamEncoder.write(java.base@17.0.7/StreamEncoder.java:132) - locked <0x00000000e1e32e98> (a java.io.OutputStreamWriter) at sun.nio.cs.StreamEncoder.write(java.base@17.0.7/StreamEncoder.java:142) at java.io.OutputStreamWriter.write(java.base@17.0.7/OutputStreamWriter.java:223) at org.eclipse.angus.mail.handlers.text_plain.writeTo(text_plain.java:139) at jakarta.activation.ObjectDataContentHandler.writeTo(DataHandler.java:866) at jakarta.activation.DataHandler.writeTo(DataHandler.java:291) at jakarta.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1683) at jakarta.mail.internet.MimeMessage.writeTo(MimeMessage.java:1911) at org.eclipse.angus.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1305) - locked <0x00000000e1e330b8> (a org.eclipse.angus.mail.smtp.SMTPTransport) at jakarta.mail.Transport.send0(Transport.java:233) at jakarta.mail.Transport.send(Transport.java:102) at org.eclipse.angus.mail.util.logging.MailHandler.send(MailHandler.java:2965) at org.eclipse.angus.mail.util.logging.MailHandler.publish0(MailHandler.java:725) at org.eclipse.angus.mail.util.logging.MailHandler.publish(MailHandler.java:678) at org.jboss.logmanager.handlers.AsyncHandler$AsyncTask.run(AsyncHandler.java:206) at java.lang.Thread.run(java.base@17.0.7/Thread.java:833) "Attach Listener" #17 daemon prio=9 os_prio=0 cpu=0.73ms elapsed=0.11s tid=0x0000564b05024db0 nid=0xb2e waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "VM Thread" os_prio=0 cpu=18.09ms elapsed=36.53s tid=0x0000564b0340e7b0 nid=0xae4 runnable "GC Thread#0" os_prio=0 cpu=58.18ms elapsed=36.55s tid=0x0000564b033955b0 nid=0xadf runnable "GC Thread#1" os_prio=0 cpu=108.51ms elapsed=31.18s tid=0x0000564b03e50760 nid=0xaf3 runnable "GC Thread#2" os_prio=0 cpu=53.24ms elapsed=31.15s tid=0x0000564b03f0f730 nid=0xaf4 runnable "GC Thread#3" os_prio=0 cpu=4.80ms elapsed=31.15s tid=0x0000564b03f10400 nid=0xaf5 runnable "G1 Main Marker" os_prio=0 cpu=0.44ms elapsed=36.55s tid=0x0000564b0339ae80 nid=0xae0 runnable "G1 Conc#0" os_prio=0 cpu=0.37ms elapsed=36.55s tid=0x0000564b0339c0b0 nid=0xae1 runnable "G1 Refine#0" os_prio=0 cpu=0.34ms elapsed=36.54s tid=0x0000564b033ea0d0 nid=0xae2 runnable "G1 Service" os_prio=0 cpu=16.73ms elapsed=36.54s tid=0x0000564b033eb290 nid=0xae3 runnable "VM Periodic Task Thread" os_prio=0 cpu=46.99ms elapsed=36.45s tid=0x0000564b0355b310 nid=0xaef waiting on condition JNI global refs: 17, weak refs: 0
I think there are a few approaches to consider on changing this behavior.
- ThreadLocal or simply checking if the current thread is the worker thread could be used to detect reentrance feedback loop.
- In the current implementation sibling AsyncHandlers could end up blocking each others worker thread. It would seem that any policy change should consider that as a test case.
- One policy to consider is if AsyncHandler detects reentrance, pass the current record to `publishToNestedHandlers` effectively barging the queue instead of blocking the worker thread. This would allow the reentrance code to execute in the MailHandler allowing the record to be dealt with. Other 3rd party handlers should be doing the same type of reentrance checking.
- An alternate policy is if AsyncHandler detects reentrance, just drop any record created by reentrance. This might be the safer choice even though it ignores the overflow policy of BLOCK.
- duplicates
-
LOGMGR-343 Check for reentry in an AyncHandler
- Resolved