Single error message for SprinIO service failure. Re-work progress.

This commit is contained in:
aboyko
2023-10-11 13:42:44 -04:00
parent 8ef70e9e01
commit 4fe5be7711
5 changed files with 89 additions and 43 deletions

View File

@@ -42,16 +42,16 @@ public class BootVersionValidationConfig {
return new UpdateBootVersion(server.getDiagnosticSeverityProvider(), bootUpgradeOpt, projectsProvider);
}
@Bean SpringIoProjectsProvider springProjectsProvider(BootJavaConfig config, RestTemplateFactory restTemplateFactory) {
return new SpringIoProjectsProvider(config, restTemplateFactory);
@Bean SpringIoProjectsProvider springProjectsProvider(SimpleLanguageServer server, BootJavaConfig config, RestTemplateFactory restTemplateFactory) {
return new SpringIoProjectsProvider(config, restTemplateFactory, server.getProgressService(), server.getMessageService(), 30_000);
}
@Bean GenerationsValidator generationsValidator(SimpleLanguageServer server, SpringProjectsProvider projectsProvider) {
return new GenerationsValidator(server.getDiagnosticSeverityProvider(), projectsProvider);
}
@Bean ProjectVersionDiagnosticProvider projectVersionDiagnosticProvider(SimpleLanguageServer server, List<VersionValidator> validators) {
return new ProjectVersionDiagnosticProvider(server.getProgressService(), server.getMessageService(), validators);
@Bean ProjectVersionDiagnosticProvider projectVersionDiagnosticProvider(List<VersionValidator> validators) {
return new ProjectVersionDiagnosticProvider(validators);
}
@ConditionalOnMissingClass("org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness")

View File

@@ -0,0 +1,21 @@
/*******************************************************************************
* Copyright (c) 2023 VMware, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.validation.generations;
public class CachedErrorStateException extends Exception {
private static final long serialVersionUID = 1L;
public CachedErrorStateException(Throwable t) {
super(t);
}
}

View File

@@ -24,9 +24,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.Version;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.MessageService;
import org.springframework.ide.vscode.commons.languageserver.PercentageProgressTask;
import org.springframework.ide.vscode.commons.languageserver.ProgressService;
public class ProjectVersionDiagnosticProvider {
@@ -34,13 +31,7 @@ public class ProjectVersionDiagnosticProvider {
private final List<VersionValidator> validators;
private ProgressService progressService;
private MessageService messageService;
public ProjectVersionDiagnosticProvider(ProgressService progressService, MessageService messageService, List<VersionValidator> validators) {
this.progressService = progressService;
this.messageService = messageService;
public ProjectVersionDiagnosticProvider(List<VersionValidator> validators) {
this.validators = validators;
}
@@ -57,33 +48,24 @@ public class ProjectVersionDiagnosticProvider {
if (!applicableValidators.isEmpty()) {
PercentageProgressTask progress = progressService.createPercentageProgressTask(
"validate-" + javaProject.getElementName(),
applicableValidators.size(),
"Validating Spring Boot Version of project '%s'".formatted(javaProject.getElementName()));
try {
Version javaProjectVersion = SpringProjectUtil.getSpringBootVersion(javaProject);
Version javaProjectVersion = SpringProjectUtil.getSpringBootVersion(javaProject);
if (javaProjectVersion == null) {
log.warn("Unable to resolve version for project: " + javaProject.getLocationUri().toASCIIString());
return new DiagnosticResult(buildFileUri, Collections.emptyList());
}
if (javaProjectVersion == null) {
log.warn("Unable to resolve version for project: " + javaProject.getLocationUri().toASCIIString());
return new DiagnosticResult(buildFileUri, Collections.emptyList());
}
for (VersionValidator validator : applicableValidators) {
try {
Collection<Diagnostic> batch = validator.validate(javaProject, javaProjectVersion);
if (batch != null) {
diagnostics.addAll(batch);
}
} catch (Exception e) {
messageService.error("Failed Spring Boot version validation for project '%s': %s".formatted(javaProject.getElementName(), e.getMessage()));
log.error("", e);
for (VersionValidator validator : applicableValidators) {
try {
Collection<Diagnostic> batch = validator.validate(javaProject, javaProjectVersion);
if (batch != null) {
diagnostics.addAll(batch);
}
progress.increment();
} catch (CachedErrorStateException e) {
// ignore the cached error state
} catch (Exception e) {
log.error("", e);
}
} finally {
progress.done();
}
}

View File

@@ -12,12 +12,16 @@ package org.springframework.ide.vscode.boot.validation.generations;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.springframework.ide.vscode.boot.app.BootJavaConfig;
import org.springframework.ide.vscode.boot.app.RestTemplateFactory;
import org.springframework.ide.vscode.boot.validation.generations.json.ResolvedSpringProject;
import org.springframework.ide.vscode.boot.validation.generations.json.SpringProject;
import org.springframework.ide.vscode.boot.validation.generations.json.SpringProjects;
import org.springframework.ide.vscode.commons.languageserver.IndefiniteProgressTask;
import org.springframework.ide.vscode.commons.languageserver.MessageService;
import org.springframework.ide.vscode.commons.languageserver.ProgressService;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
@@ -31,13 +35,23 @@ import com.google.common.collect.ImmutableMap.Builder;
*
*/
public class SpringIoProjectsProvider implements SpringProjectsProvider {
private SpringProjectsClient client;
private Map<String, ResolvedSpringProject> cache;
private RestTemplateFactory restTemplateFactory;
final private ProgressService progressService;
final private MessageService messageService;
final private long errorStateCachingTime;
private long lastErrorTime;
private Optional<Throwable> errorState;
public SpringIoProjectsProvider(BootJavaConfig config, RestTemplateFactory restTemplateFactory) {
public SpringIoProjectsProvider(BootJavaConfig config, RestTemplateFactory restTemplateFactory, ProgressService progressService, MessageService messageService, long errorStateCachingTime) {
this.restTemplateFactory = restTemplateFactory;
this.progressService = progressService;
this.messageService = messageService;
this.errorStateCachingTime = errorStateCachingTime;
clearErrorState();
updateIoApiUri(config.getSpringIOApiUrl());
config.addListener(v -> updateIoApiUri(config.getSpringIOApiUrl()));
}
@@ -46,6 +60,7 @@ public class SpringIoProjectsProvider implements SpringProjectsProvider {
if (client == null || !uri.equals(client.getUrl())) {
this.client = new SpringProjectsClient(uri, restTemplateFactory);
cache = null;
clearErrorState();
}
}
@@ -63,12 +78,40 @@ public class SpringIoProjectsProvider implements SpringProjectsProvider {
private Map<String, ResolvedSpringProject> cache() throws Exception {
if (cache == null) {
SpringProjects springProjects = client.getSpringProjects();
cache = asMap(springProjects);
if (lastErrorTime + errorStateCachingTime < System.currentTimeMillis()) {
IndefiniteProgressTask progress = progressService.createIndefiniteProgressTask("fetching-from-spring-io", "Fetching Generations from Spring IO", null);
try {
SpringProjects springProjects = client.getSpringProjects();
cache = asMap(springProjects);
// Wipe out error state
clearErrorState();
} catch (Exception e) {
messageService.error("Failed to fetch Generation from Spring IO: %s".formatted(e.getMessage()));
setErrorState(e);
throw e;
} finally {
progress.done();
}
} else {
// The error state hasn't expired - throw a cached error state exception
if (errorState.isPresent()) {
throw new CachedErrorStateException(errorState.get());
}
}
}
return cache != null ? cache : ImmutableMap.of();
}
private void clearErrorState() {
errorState = Optional.empty();
lastErrorTime = 0;
}
private void setErrorState(Throwable t) {
errorState = Optional.of(t);
lastErrorTime = System.currentTimeMillis();
}
private Map<String, ResolvedSpringProject> asMap(SpringProjects springProjects) {
Builder<String, ResolvedSpringProject> builder = ImmutableMap.builder();

View File

@@ -56,7 +56,7 @@ public class ProjectGenerationsValidationTest {
@Test
void testProjectsInfoFromSpringIo() throws Exception {
SpringProjectsProvider cache = new SpringIoProjectsProvider(config, restTemplateFactory);
SpringProjectsProvider cache = new SpringIoProjectsProvider(config, restTemplateFactory, harness.getServer().getProgressService(), harness.getServer().getMessageService(), -1);
SpringProject project = cache.getProject("spring-boot");
assertNotNull(project);