com.transferwise.common.gracefulshutdown.strategies.BaseReactiveResourceShutdownStrategy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tw-graceful-shutdown Show documentation
Show all versions of tw-graceful-shutdown Show documentation
TransferWise Graceful Shutdown - no noise and errors during releases.
The newest version!
package com.transferwise.common.gracefulshutdown.strategies;
import com.transferwise.common.gracefulshutdown.GracefulShutdownIgnore;
import com.transferwise.common.gracefulshutdown.GracefulShutdownStrategy;
import com.transferwise.common.gracefulshutdown.config.GracefulShutdownProperties;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
@Slf4j
public abstract class BaseReactiveResourceShutdownStrategy implements GracefulShutdownStrategy {
@SuppressFBWarnings("CT")
public BaseReactiveResourceShutdownStrategy(@NonNull Class resourceType, @NonNull ApplicationContext applicationContext,
@NonNull GracefulShutdownProperties gracefulShutdownProperties) {
this.resourceType = resourceType;
this.applicationContext = applicationContext;
this.gracefulShutdownProperties = gracefulShutdownProperties;
}
@NonNull
// Because of Java type erasure we can't get type of generic parameter after compilation.
// To access it at runtime we have to provide and save it explicitly.
private final Class resourceType;
protected Class getResourceType() {
return this.resourceType;
}
@NonNull
private final ApplicationContext applicationContext;
@Getter(AccessLevel.PROTECTED)
@NonNull
private final GracefulShutdownProperties gracefulShutdownProperties;
@Getter(AccessLevel.PROTECTED)
private final Scheduler shutdownScheduler = Schedulers.newBoundedElastic(
10,
100_000,
"ShutdownWorker_" + this.getClass().getSimpleName()
);
private final List addedResources = new ArrayList<>();
private final AtomicBoolean isShutdownAllowed = new AtomicBoolean(false);
/**
* {@link Duration} allowed for resource to force shut down. If not shut down within this time - error will be logged.
*
* @return {@link Duration}
*/
private Duration getResourceForcedShutdownTimeout() {
// This checks incorrect configuration. Timeout error will be logged.
if (getStrategyShutdownDelay().toMillis() > getResourceFullShutdownTimeoutMs()) {
return Duration.ZERO;
}
// use remaining time for forced shutdown
return Duration.ofMillis(getResourceFullShutdownTimeoutMs() - getResourceGracefulShutdownTimeout().toMillis());
}
/**
* Interval between checks of the resource termination status. Used by {@link #waitTermination}
*
* @return {@link Duration} between termination check
*/
private Duration getDelayBetweenTerminationCheck() {
return Duration.ofMillis(this.getGracefulShutdownProperties().getResourceCheckIntervalTimeMs());
}
/**
* Will delay strategy shutdown for this {@link Duration}.
* This will additionally affect {@link #getResourceGracefulShutdownTimeout}
* and {@link #getResourceForcedShutdownTimeout}
*
* Read {@link #getResourceGracefulShutdownTimeShare} for more info.
*
*
* @return {@link Duration} to delay strategy shutdown.
*/
protected Duration getStrategyShutdownDelay() {
return Duration.ZERO;
}
/**
* {@link Duration} allowed for strategy to shut down all resources.
* @return {@link Duration}
*/
protected Duration getStrategyShutdownTimeout() {
return Duration.ofMillis(this.gracefulShutdownProperties.getShutdownTimeoutMs());
}
/**
* Time in Ms within resource should shut down.
* @return Time in Ms
*/
protected int getResourceFullShutdownTimeoutMs() {
// resource should shut down a little earlier than StrategyShutdownTimeout
int result = this.gracefulShutdownProperties.getShutdownTimeoutMs() - 250;
if (result < 1000) {
result = this.gracefulShutdownProperties.getShutdownTimeoutMs();
}
return result;
}
/**
* Split ResourceFullShutdownTimeout between graceful and forced shutdown. Value between 0 and 1 is expected where 1 means 100%.
*
* - {@link #getResourceGracefulShutdownTimeout} =
* ({@link #getResourceFullShutdownTimeoutMs} -
* {@link #getStrategyShutdownDelay}) *
* {@link #getResourceGracefulShutdownTimeShare}
*
* - {@link #getResourceForcedShutdownTimeout} =
* {@link #getResourceFullShutdownTimeoutMs} -
* {@link #getResourceGracefulShutdownTimeout}
*
*
*
* @return time share of ResourceFullShutdownTimeout dedicated to graceful shutdown
*/
protected double getResourceGracefulShutdownTimeShare() {
return 0.9d;
}
/**
* {@link Duration} allowed for resource to shut down gracefully. If not shut down within this time -
* {@link #shutdownResourceForced} will be called.
*
* @return {@link Duration}
*/
private Duration getResourceGracefulShutdownTimeout() {
// This checks incorrect configuration. Timeout error will be logged.
if (getStrategyShutdownDelay().toMillis() > getResourceFullShutdownTimeoutMs()) {
return Duration.ZERO;
}
// getStrategyShutdownDelay time of getResourceFullShutdownTimeoutMs was already used.
// use ResourceGracefulShutdownTimeShare of remaining time for graceful shutdown
double gracefulShutdownShare = Math.min(getResourceGracefulShutdownTimeShare(), 1d);
int resourceGracefulShutdownTimeMS = (int) ((getResourceFullShutdownTimeoutMs() - getStrategyShutdownDelay().toMillis()) * gracefulShutdownShare);
return Duration.ofMillis(resourceGracefulShutdownTimeMS);
}
/**
* Prepare {@link Set} of resources for shutdown by extracting Beans of {@link #getResourceType()} from application context
* and add manually added resources by {@link #addResource}.
* @return {@link Set} of resources for shutdown
*/
public Set getResourcesForShutdown() {
Set
© 2015 - 2024 Weber Informatics LLC | Privacy Policy