From 7d2047cdbd6f440cd2ce638947795c81c537db28 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 3 May 2023 18:16:32 +0200 Subject: [PATCH] Prevent JVM shutdown before checkpoint See gh-30242 --- .../support/DefaultLifecycleProcessor.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java b/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java index ecf2029d4e..beb9579519 100644 --- a/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java @@ -28,6 +28,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; @@ -471,8 +472,24 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor */ private class CracResourceAdapter implements org.crac.Resource { + @Nullable + private CyclicBarrier barrier; + @Override public void beforeCheckpoint(org.crac.Context context) { + // A non-daemon thread for preventing an accidental JVM shutdown before the checkpoint + this.barrier = new CyclicBarrier(2); + + Thread thread = new Thread(() -> { + awaitPreventShutdownBarrier(); + // Checkpoint happens here + awaitPreventShutdownBarrier(); + }, "prevent-shutdown"); + + thread.setDaemon(false); + thread.start(); + awaitPreventShutdownBarrier(); + logger.debug("Stopping Spring-managed lifecycle beans before JVM snapshot checkpoint"); stopForRestart(); } @@ -481,6 +498,21 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor public void afterRestore(org.crac.Context context) { logger.debug("Restarting Spring-managed lifecycle beans after JVM snapshot restore"); restartAfterStop(); + + // Barrier for prevent-shutdown thread not needed anymore + awaitPreventShutdownBarrier(); + this.barrier = null; + } + + private void awaitPreventShutdownBarrier() { + try { + if (this.barrier != null) { + this.barrier.await(); + } + } + catch (Exception ex) { + logger.trace("Exception from prevent-shutdown barrier", ex); + } } }