added RestartStrategies to be able to swap the context recreation strategy

This commit is contained in:
Sebastian Sdorra
2019-06-19 11:53:58 +02:00
parent f747be4331
commit 33702e0e9d
4 changed files with 219 additions and 45 deletions

View File

@@ -37,7 +37,6 @@ import com.github.legman.Subscribe;
import com.google.inject.servlet.GuiceFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.event.RecreateEventBusEvent;
import sonia.scm.event.ScmEventBus;
import javax.servlet.FilterConfig;
@@ -50,63 +49,29 @@ import javax.servlet.ServletException;
*
* @author Sebastian Sdorra
*/
public class BootstrapContextFilter extends GuiceFilter
{
public class BootstrapContextFilter extends GuiceFilter {
/**
* the logger for BootstrapContextFilter
*/
private static final Logger logger =
LoggerFactory.getLogger(BootstrapContextFilter.class);
//~--- methods --------------------------------------------------------------
private static final Logger LOG = LoggerFactory.getLogger(BootstrapContextFilter.class);
private final BootstrapContextListener listener = new BootstrapContextListener();
/**
* Restart the whole webapp context.
*
*
* @param event restart event
*
* @throws ServletException
*/
@Subscribe
public void handleRestartEvent(RestartEvent event) throws ServletException
{
logger.warn("received restart event from {} with reason: {}",
event.getCause(), event.getReason());
if (filterConfig == null)
{
logger.error("filter config is null, scm-manager is not initialized");
}
else
{
logger.warn("destroy filter pipeline, because of a received restart event");
destroy();
logger.warn("send recreate eventbus event");
ScmEventBus.getInstance().post(new RecreateEventBusEvent());
ScmEventBus.getInstance().register(this);
logger.warn("reinitialize filter pipeline, because of a received restart event");
initGuice();
}
}
/** Field description */
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
initGuice();
logger.info("register for restart events");
LOG.info("register for restart events");
ScmEventBus.getInstance().register(this);
}
public void initGuice() throws ServletException {
private void initGuice() throws ServletException {
super.init(filterConfig);
listener.contextInitialized(new ServletContextEvent(filterConfig.getServletContext()));
@@ -119,8 +84,39 @@ public class BootstrapContextFilter extends GuiceFilter
ServletContextCleaner.cleanup(filterConfig.getServletContext());
}
//~--- fields ---------------------------------------------------------------
/**
* Restart SCM-Manager.
*
* @param event restart event
*/
@Subscribe
public void handleRestartEvent(RestartEvent event) {
LOG.warn("received restart event from {} with reason: {}",
event.getCause(), event.getReason());
if (filterConfig == null) {
LOG.error("filter config is null, scm-manager is not initialized");
} else {
RestartStrategy restartStrategy = RestartStrategy.get();
restartStrategy.restart(new GuiceInjectionContext());
}
}
private class GuiceInjectionContext implements RestartStrategy.InjectionContext {
@Override
public void initialize() {
try {
BootstrapContextFilter.this.initGuice();
} catch (ServletException e) {
throw new IllegalStateException("failed to initialize guice", e);
}
}
@Override
public void destroy() {
BootstrapContextFilter.this.destroy();
}
}
/** Field description */
private FilterConfig filterConfig;
}

View File

@@ -0,0 +1,50 @@
package sonia.scm.boot;
import com.google.common.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.event.RecreateEventBusEvent;
import sonia.scm.event.ScmEventBus;
import java.util.concurrent.atomic.AtomicLong;
/**
* Restart strategy implementation which destroy the injection context and re initialize it.
*/
public class InjectionContextRestartStrategy implements RestartStrategy {
private static final AtomicLong INSTANCE_COUNTER = new AtomicLong();
private static final Logger LOG = LoggerFactory.getLogger(InjectionContextRestartStrategy.class);
private long waitInMs = 250L;
@VisibleForTesting
void setWaitInMs(long waitInMs) {
this.waitInMs = waitInMs;
}
@Override
public void restart(InjectionContext context) {
LOG.warn("destroy injection context");
context.destroy();
LOG.warn("send recreate eventbus event");
ScmEventBus.getInstance().post(new RecreateEventBusEvent());
// restart context delayed, to avoid timing problems
new Thread(() -> {
try {
Thread.sleep(waitInMs);
LOG.warn("reinitialize injection context");
context.initialize();
LOG.debug("re register injection context for events");
ScmEventBus.getInstance().register(context);
} catch ( Exception ex) {
LOG.error("failed to restart", ex);
}
}, "Delayed-Restart-" + INSTANCE_COUNTER.incrementAndGet()).start();
}
}

View File

@@ -0,0 +1,38 @@
package sonia.scm.boot;
/**
* Strategy for restarting SCM-Manager.
*/
public interface RestartStrategy {
/**
* Context for Injection in SCM-Manager.
*/
interface InjectionContext {
/**
* Initialize the injection context.
*/
void initialize();
/**
* Destroys the injection context.
*/
void destroy();
}
/**
* Restart SCM-Manager.
* @param context injection context
*/
void restart(InjectionContext context);
/**
* Returns the configured strategy.
*
* @return configured strategy
*/
static RestartStrategy get() {
return new InjectionContextRestartStrategy();
}
}