If your microservice stops responding from time to time, and they only way out is to kill it with SIGINT or SIGTERM then adding a shutdown hook might be the way to go. Do note that this will not work if you kill the process with SIGKILL (-9), cause that will result in an unclean shutdown.
Some of this code is heavily influenced by Print all of the thread’s information and stack traces : Exception « Development « Java Tutorial. But has been translated into Scala, and cleaned up a little.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
import java.io.PrintWriter import java.lang.management.ManagementFactory object TryOutShutdownHook { def doStuff() = { (1 to 1000).foreach( _ => { print(".") Thread.sleep(1000) }) } def main(args: Array[String]): Unit = { sys.addShutdownHook({ println("Shutdown hook!") ThreadUtils.printThreadInfo(new PrintWriter(System.out),"Threads during shutdown") }) doStuff() } } object ThreadUtils { private val threadBean = ManagementFactory.getThreadMXBean def setContentionTracing(on: Boolean): Unit = { threadBean.setThreadContentionMonitoringEnabled( on ) } private def getTaskName(id: Long, name: String): String = { if (name == null) id.toString else id + " (" + name + ")" } /** * Print all of the thread's information and stack traces. * * @param stream * the stream to * @param title * a string title for the stack trace */ def printThreadInfo(stream: PrintWriter, title: String): Unit = { val STACK_DEPTH = 20 val contention = threadBean.isThreadContentionMonitoringEnabled val threadIds = threadBean.getAllThreadIds stream.println("Process Thread Dump: " + title) stream.println(threadIds.length + " active threads") for (tid <- threadIds) { val info = threadBean.getThreadInfo(tid, STACK_DEPTH) if (info == null) { stream.println(" Inactive") } else { stream.println("Thread " + getTaskName(info.getThreadId, info.getThreadName) + ":") val state = info.getThreadState stream.println(" State: " + state) stream.println(" Blocked count: " + info.getBlockedCount) stream.println(" Waited count: " + info.getWaitedCount) if (contention) { stream.println(" Blocked time: " + info.getBlockedTime) stream.println(" Waited time: " + info.getWaitedTime) } if (state eq Thread.State.WAITING) stream.println(" Waiting on " + info.getLockName) else if (state eq Thread.State.BLOCKED) { stream.println(" Blocked on " + info.getLockName) stream.println(" Blocked by " + getTaskName(info.getLockOwnerId, info.getLockOwnerName)) } stream.println(" Stack:") for (frame <- info.getStackTrace) { stream.println(" " + frame.toString) } } } stream.flush() } } |
The output would look something like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
...........................Shutdown hook! Process Thread Dump: Threads during shutdown 8 active threads Thread 11 (shutdownHook1): State: RUNNABLE Blocked count: 0 Waited count: 0 Stack: sun.management.ThreadImpl.getThreadInfo1(Native Method) sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:178) sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:139) ThreadUtils$.$anonfun$printThreadInfo$1(TryOutShutdownHook.scala:56) ThreadUtils$$$Lambda$7/1354382162.apply$mcVJ$sp(Unknown Source) scala.runtime.java8.JFunction1$mcVJ$sp.apply(JFunction1$mcVJ$sp.java:23) scala.collection.IndexedSeqOptimized.foreach(IndexedSeqOptimized.scala:36) scala.collection.IndexedSeqOptimized.foreach$(IndexedSeqOptimized.scala:33) scala.collection.mutable.ArrayOps$ofLong.foreach(ArrayOps.scala:258) ThreadUtils$.printThreadInfo(TryOutShutdownHook.scala:55) TryOutShutdownHook$.$anonfun$main$1(TryOutShutdownHook.scala:18) TryOutShutdownHook$$$Lambda$1/728890494.apply$mcV$sp(Unknown Source) scala.sys.ShutdownHookThread$$anon$1.run(ShutdownHookThread.scala:37) Thread 13 (SIGTERM handler): State: WAITING Blocked count: 0 Waited count: 1 Waiting on scala.sys.ShutdownHookThread$$anon$1@506c589e Stack: java.lang.Object.wait(Native Method) java.lang.Thread.join(Thread.java:1252) java.lang.Thread.join(Thread.java:1326) java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:107) java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:46) java.lang.Shutdown.runHooks(Shutdown.java:123) java.lang.Shutdown.sequence(Shutdown.java:167) java.lang.Shutdown.exit(Shutdown.java:212) java.lang.Terminator$1.handle(Terminator.java:52) sun.misc.Signal$1.run(Signal.java:212) java.lang.Thread.run(Thread.java:748) Thread 12 (Attach Listener): State: RUNNABLE Blocked count: 0 Waited count: 0 Stack: Thread 5 (Monitor Ctrl-Break): State: RUNNABLE Blocked count: 0 Waited count: 0 Stack: java.net.SocketInputStream.socketRead0(Native Method) java.net.SocketInputStream.socketRead(SocketInputStream.java:116) java.net.SocketInputStream.read(SocketInputStream.java:171) java.net.SocketInputStream.read(SocketInputStream.java:141) sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) java.io.InputStreamReader.read(InputStreamReader.java:184) java.io.BufferedReader.fill(BufferedReader.java:161) java.io.BufferedReader.readLine(BufferedReader.java:324) java.io.BufferedReader.readLine(BufferedReader.java:389) com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64) Thread 4 (Signal Dispatcher): State: RUNNABLE Blocked count: 0 Waited count: 0 Stack: Thread 3 (Finalizer): State: WAITING Blocked count: 1 Waited count: 2 Waiting on java.lang.ref.ReferenceQueue$Lock@79c01878 Stack: java.lang.Object.wait(Native Method) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165) java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216) Thread 2 (Reference Handler): State: WAITING Blocked count: 1 Waited count: 1 Waiting on java.lang.ref.Reference$Lock@2b1227e6 Stack: java.lang.Object.wait(Native Method) java.lang.Object.wait(Object.java:502) java.lang.ref.Reference.tryHandlePending(Reference.java:191) java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) Thread 1 (main): State: TIMED_WAITING Blocked count: 0 Waited count: 27 Stack: java.lang.Thread.sleep(Native Method) TryOutShutdownHook$.$anonfun$doStuff$1(TryOutShutdownHook.scala:10) TryOutShutdownHook$$$Lambda$6/2047526627.apply$mcVI$sp(Unknown Source) scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:158) TryOutShutdownHook$.doStuff(TryOutShutdownHook.scala:8) TryOutShutdownHook$.main(TryOutShutdownHook.scala:21) TryOutShutdownHook.main(TryOutShutdownHook.scala) Process finished with exit code 143 (interrupted by signal 15: SIGTERM) |
It is truly a nice and helpful piece of information. I am glad that you simply shared this helpful info with us. And also thank you for your detailed explain.
Wonderful information, thanks a lot for sharing kind of information. Your website gives the best and the most interesting information.
Thanks a ton once again, Regards