diff options
-rw-r--r-- | configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java | 57 | ||||
-rw-r--r-- | configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java | 66 |
2 files changed, 64 insertions, 59 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java index b14fe5bcac9..8a02383ad0b 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java @@ -6,7 +6,6 @@ import com.google.inject.Inject; import com.yahoo.cloud.config.ConfigserverConfig; import com.yahoo.component.Version; import com.yahoo.component.Vtag; -import com.yahoo.concurrent.DaemonThreadFactory; import com.yahoo.config.FileReference; import com.yahoo.config.application.api.ApplicationFile; import com.yahoo.config.application.api.ApplicationMetaData; @@ -62,17 +61,10 @@ import java.time.Clock; import java.time.Duration; import java.time.Instant; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -460,7 +452,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye } } - private Set<ApplicationId> listApplications() { + Set<ApplicationId> listApplications() { return tenantRepository.getAllTenants().stream() .flatMap(tenant -> tenant.getApplicationRepo().listApplications().stream()) .collect(Collectors.toSet()); @@ -684,53 +676,6 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye } } - boolean redeployAllApplications(Duration maxDuration, Duration sleepBetweenRetries) throws InterruptedException { - Instant end = Instant.now().plus(maxDuration); - Set<ApplicationId> applicationsNotRedeployed = listApplications(); - do { - applicationsNotRedeployed = redeployApplications(applicationsNotRedeployed); - if ( ! applicationsNotRedeployed.isEmpty()) { - Thread.sleep(sleepBetweenRetries.toMillis()); - } - } while ( ! applicationsNotRedeployed.isEmpty() && Instant.now().isBefore(end)); - - if ( ! applicationsNotRedeployed.isEmpty()) { - log.log(LogLevel.ERROR, "Redeploying applications not finished after " + maxDuration + - ", exiting, applications that failed redeployment: " + applicationsNotRedeployed); - return false; - } - return true; - } - - // Returns the set of applications that failed to redeploy - private Set<ApplicationId> redeployApplications(Set<ApplicationId> applicationIds) throws InterruptedException { - ExecutorService executor = Executors.newFixedThreadPool(configserverConfig.numParallelTenantLoaders(), - new DaemonThreadFactory("redeploy apps")); - // Keep track of deployment per application - Map<ApplicationId, Future<?>> futures = new HashMap<>(); - Set<ApplicationId> failedDeployments = new HashSet<>(); - - for (ApplicationId appId : applicationIds) { - Optional<com.yahoo.config.provision.Deployment> deploymentOptional = deployFromLocalActive(appId, true /* bootstrap */); - if ( ! deploymentOptional.isPresent()) continue; - - futures.put(appId, executor.submit(deploymentOptional.get()::activate)); - } - - for (Map.Entry<ApplicationId, Future<?>> f : futures.entrySet()) { - try { - f.getValue().get(); - } catch (ExecutionException e) { - ApplicationId app = f.getKey(); - log.log(LogLevel.WARNING, "Redeploying " + app + " failed, will retry", e); - failedDeployments.add(app); - } - } - executor.shutdown(); - executor.awaitTermination(365, TimeUnit.DAYS); // Timeout should never happen - return failedDeployments; - } - private LocalSession getExistingSession(Tenant tenant, ApplicationId applicationId) { TenantApplications applicationRepo = tenant.getApplicationRepo(); return getLocalSession(tenant, applicationRepo.getSessionIdForApplication(applicationId)); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java index 50052ac856c..46be61964ce 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java @@ -2,8 +2,11 @@ package com.yahoo.vespa.config.server; import com.google.inject.Inject; +import com.yahoo.cloud.config.ConfigserverConfig; import com.yahoo.component.AbstractComponent; import com.yahoo.concurrent.DaemonThreadFactory; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.Deployment; import com.yahoo.container.handler.VipStatus; import com.yahoo.container.jdisc.state.StateMonitor; import com.yahoo.log.LogLevel; @@ -12,8 +15,16 @@ import com.yahoo.vespa.config.server.version.VersionState; import java.time.Duration; import java.time.Instant; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; /** * Main component that bootstraps and starts config server threads. @@ -39,6 +50,7 @@ public class ConfigServerBootstrap extends AbstractComponent implements Runnable private final VersionState versionState; private final StateMonitor stateMonitor; private final VipStatus vipStatus; + private final ConfigserverConfig configserverConfig; private final Duration maxDurationOfRedeployment; private final Duration sleepTimeWhenRedeployingFails; private final RedeployingApplicationsFails exitIfRedeployingApplicationsFails; @@ -63,8 +75,9 @@ public class ConfigServerBootstrap extends AbstractComponent implements Runnable this.stateMonitor = stateMonitor; this.serverThread = new Thread(this, "configserver main"); this.vipStatus = vipStatus; - this.maxDurationOfRedeployment = Duration.ofSeconds(applicationRepository.configserverConfig().maxDurationOfBootstrap()); - this.sleepTimeWhenRedeployingFails = Duration.ofSeconds(applicationRepository.configserverConfig().sleepTimeWhenRedeployingFails()); + this.configserverConfig = applicationRepository.configserverConfig(); + this.maxDurationOfRedeployment = Duration.ofSeconds(configserverConfig.maxDurationOfBootstrap()); + this.sleepTimeWhenRedeployingFails = Duration.ofSeconds(configserverConfig.sleepTimeWhenRedeployingFails()); this.exitIfRedeployingApplicationsFails = exitIfRedeployingApplicationsFails; rpcServerExecutor = Executors.newSingleThreadExecutor(new DaemonThreadFactory("config server RPC server")); initializing(); // Initially take server out of rotation @@ -91,7 +104,7 @@ public class ConfigServerBootstrap extends AbstractComponent implements Runnable log.log(LogLevel.INFO, "Configserver upgrading from " + versionState.storedVersion() + " to " + versionState.currentVersion() + ". Redeploying all applications"); try { - if ( ! applicationRepository.redeployAllApplications(maxDurationOfRedeployment, sleepTimeWhenRedeployingFails)) { + if ( ! redeployAllApplications()) { redeployingApplicationsFailed(); return; // Status will not be set to 'up' since we return here } @@ -163,5 +176,52 @@ public class ConfigServerBootstrap extends AbstractComponent implements Runnable if (exitIfRedeployingApplicationsFails == RedeployingApplicationsFails.EXIT_JVM) System.exit(1); } + private boolean redeployAllApplications() throws InterruptedException { + Instant end = Instant.now().plus(maxDurationOfRedeployment); + Set<ApplicationId> applicationsNotRedeployed = applicationRepository.listApplications(); + do { + applicationsNotRedeployed = redeployApplications(applicationsNotRedeployed); + if ( ! applicationsNotRedeployed.isEmpty()) { + Thread.sleep(sleepTimeWhenRedeployingFails.toMillis()); + } + } while ( ! applicationsNotRedeployed.isEmpty() && Instant.now().isBefore(end)); + + if ( ! applicationsNotRedeployed.isEmpty()) { + log.log(LogLevel.ERROR, "Redeploying applications not finished after " + maxDurationOfRedeployment + + ", exiting, applications that failed redeployment: " + applicationsNotRedeployed); + return false; + } + return true; + } + + // Returns the set of applications that failed to redeploy + private Set<ApplicationId> redeployApplications(Set<ApplicationId> applicationIds) throws InterruptedException { + ExecutorService executor = Executors.newFixedThreadPool(configserverConfig.numParallelTenantLoaders(), + new DaemonThreadFactory("redeploy apps")); + // Keep track of deployment per application + Map<ApplicationId, Future<?>> futures = new HashMap<>(); + Set<ApplicationId> failedDeployments = new HashSet<>(); + + for (ApplicationId appId : applicationIds) { + Optional<Deployment> deploymentOptional = applicationRepository.deployFromLocalActive(appId, true /* bootstrap */); + if ( ! deploymentOptional.isPresent()) continue; + + futures.put(appId, executor.submit(deploymentOptional.get()::activate)); + } + + for (Map.Entry<ApplicationId, Future<?>> f : futures.entrySet()) { + try { + f.getValue().get(); + } catch (ExecutionException e) { + ApplicationId app = f.getKey(); + log.log(LogLevel.WARNING, "Redeploying " + app + " failed, will retry", e); + failedDeployments.add(app); + } + } + executor.shutdown(); + executor.awaitTermination(365, TimeUnit.DAYS); // Timeout should never happen + return failedDeployments; + } + } |