From 7f6f47b97b8a0e6758560f9d455f0e1d16d4b688 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 6 Jun 2023 19:18:34 +0200 Subject: [PATCH] Property-driven onRefresh checkpoint during application context bootstrap Closes gh-30606 --- .../support/DefaultLifecycleProcessor.java | 44 +++++++++++++++++++ 1 file changed, 44 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 7897ed8d9f9c..1c4d9009e3eb 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 @@ -34,6 +34,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.crac.CheckpointException; +import org.crac.Core; +import org.crac.RestoreException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -45,6 +48,7 @@ import org.springframework.context.Phased; import org.springframework.context.SmartLifecycle; import org.springframework.core.NativeDetector; +import org.springframework.core.SpringProperties; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -63,6 +67,26 @@ */ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactoryAware { + /** + * Property name for checkpoint restore: "spring.checkpoint.restore". + * @since 6.1 + * @see #CHECKPOINT_RESTORE_ON_REFRESH + * @see org.crac.Core#checkpointRestore() + */ + public static final String CHECKPOINT_RESTORE_PROPERTY_NAME = "spring.checkpoint.restore"; + + /** + * Recognized value for checkpoint restore property: "onRefresh". + * @since 6.1 + * @see #CHECKPOINT_RESTORE_PROPERTY_NAME + * @see org.crac.Core#checkpointRestore() + */ + public static final String CHECKPOINT_RESTORE_ON_REFRESH = "onRefresh"; + + + private final static boolean checkpointRestoreOnRefresh = CHECKPOINT_RESTORE_ON_REFRESH.equalsIgnoreCase( + SpringProperties.getProperty(CHECKPOINT_RESTORE_PROPERTY_NAME)); + private final Log logger = LogFactory.getLog(getClass()); private volatile long timeoutPerShutdownPhase = 30000; @@ -145,6 +169,10 @@ public void stop() { @Override public void onRefresh() { + if (checkpointRestoreOnRefresh) { + new CracDelegate().checkpointRestore(); + } + this.stoppedBeans = null; startBeans(true); this.running = true; @@ -462,6 +490,22 @@ public Object registerResource() { org.crac.Core.getGlobalContext().register(resourceAdapter); return resourceAdapter; } + + public void checkpointRestore() { + logger.info("Triggering JVM checkpoint/restore"); + try { + Core.checkpointRestore(); + } + catch (UnsupportedOperationException ex) { + throw new ApplicationContextException("CRaC checkpoint not supported on current JVM", ex); + } + catch (CheckpointException ex) { + throw new ApplicationContextException("Failed to take CRaC checkpoint on refresh", ex); + } + catch (RestoreException ex) { + throw new ApplicationContextException("Failed to restore CRaC checkpoint on refresh", ex); + } + } }