mirror of https://github.com/halo-dev/halo
Continue extension updation if modification conflict occurs (#2536)
#### What type of PR is this? /kind bug /area core /milestone 2.0 #### What this PR does / why we need it: When we initialize default extensions at Halo startup, updation of one extension is very likely to be failed due to modification conflict. Then, remaining extensions won't be updated anymore. Therefore, this PR resolve this problem by retrying updation with 3 times with interval 100ms and continue extension updation if modification conflict occurs. #### How to test 1. Fully initialize system(e.g.: Clear `~/halo-next` before starting Halo) 2. Update Role `authenticated` as you wish via Extension API 3. Restart Halo and check it again 4. Retry multiple times #### Does this PR introduce a user-facing change? ```release-note 修复系统默认数据无法正常更新的问题 ```pull/2546/head
parent
dbaa087936
commit
cc221d31c7
|
@ -1,6 +1,7 @@
|
|||
package run.halo.app.infra;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -9,10 +10,12 @@ import org.springframework.boot.context.event.ApplicationReadyEvent;
|
|||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.retry.Retry;
|
||||
import run.halo.app.extension.ReactiveExtensionClient;
|
||||
import run.halo.app.extension.Unstructured;
|
||||
import run.halo.app.infra.properties.HaloProperties;
|
||||
|
@ -60,18 +63,17 @@ public class ExtensionResourceInitializer {
|
|||
.map(this::listResources)
|
||||
.distinct()
|
||||
.flatMapIterable(resources -> resources)
|
||||
.doOnNext(resource -> log.debug("Initializing extension resource: {}", resource))
|
||||
.doOnNext(resource -> log.debug("Initializing extension resource from location: {}",
|
||||
resource))
|
||||
.map(resource -> new YamlUnstructuredLoader(resource).load())
|
||||
.flatMapIterable(extensions -> extensions)
|
||||
.flatMap(extension -> extensionClient.fetch(extension.groupVersionKind(),
|
||||
extension.getMetadata().getName())
|
||||
.flatMap(createdExtension -> {
|
||||
extension.getMetadata()
|
||||
.setVersion(createdExtension.getMetadata().getVersion());
|
||||
return extensionClient.update(extension);
|
||||
})
|
||||
.switchIfEmpty(Mono.defer(() -> extensionClient.create(extension)))
|
||||
)
|
||||
.doOnNext(extension -> {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Initializing extension resource: {}/{}",
|
||||
extension.groupVersionKind(), extension.getMetadata().getName());
|
||||
}
|
||||
})
|
||||
.flatMap(this::createOrUpdate)
|
||||
.doOnNext(extension -> {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Initialized extension resource: {}/{}", extension.groupVersionKind(),
|
||||
|
@ -81,6 +83,24 @@ public class ExtensionResourceInitializer {
|
|||
.then();
|
||||
}
|
||||
|
||||
private Mono<Unstructured> createOrUpdate(Unstructured extension) {
|
||||
return Mono.just(extension)
|
||||
.flatMap(ext -> extensionClient.fetch(extension.groupVersionKind(),
|
||||
extension.getMetadata().getName()))
|
||||
.flatMap(existingExt -> {
|
||||
extension.getMetadata().setVersion(existingExt.getMetadata().getVersion());
|
||||
return extensionClient.update(extension);
|
||||
})
|
||||
.switchIfEmpty(Mono.defer(() -> extensionClient.create(extension)))
|
||||
.retryWhen(Retry.fixedDelay(3, Duration.ofMillis(100))
|
||||
.filter(t -> t instanceof OptimisticLockingFailureException))
|
||||
.onErrorContinue(OptimisticLockingFailureException.class, (throwable, o) -> {
|
||||
log.warn("Failed to create or update extension resource: {}/{} due to modification "
|
||||
+ "conflict",
|
||||
extension.groupVersionKind(), extension.getMetadata().getName());
|
||||
});
|
||||
}
|
||||
|
||||
private List<Resource> listResources(String location) {
|
||||
var resolver = new PathMatchingResourcePatternResolver();
|
||||
try {
|
||||
|
|
Loading…
Reference in New Issue