mirror of https://github.com/halo-dev/halo
fix: failed to load plugin when add fixedPluginPath dynamically in development mode (#2941)
#### What type of PR is this? /kind bug /area core #### What this PR does / why we need it: 修复插件开发模式下后续增加的 fixedPluginPath 项无法被加载的问题 - 目前启动时会加载 pluginRepository 的所有 path,fixedPluginPath 被 DefaultDevelopmentPluginRepository 管理,所以在遍历 fixedPluginPath 加载时可能已经被加载过,需要判断是否被加载过,但即使被加载过也不能跳过而要继续执行创建/更新 plugin.yaml 资源的逻辑 - 创建/更新 plugin.yaml 时需要使用重试机制防止因为乐观锁冲突导致 Halo 无法启动 see #2939 for more detail #### Which issue(s) this PR fixes: Fixes #2939 #### Special notes for your reviewer: /cc @halo-dev/sig-halo #### Does this PR introduce a user-facing change? ```release-note 修复插件开发模式下后续增加的 fixedPluginPath 项无法被加载的问题 ```pull/2923/head
parent
df0e6cff49
commit
07f5b0dbcd
|
@ -1,14 +1,18 @@
|
||||||
package run.halo.app.plugin;
|
package run.halo.app.plugin;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.time.Duration;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.pf4j.PluginWrapper;
|
import org.pf4j.PluginWrapper;
|
||||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.dao.OptimisticLockingFailureException;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.util.retry.Retry;
|
||||||
import run.halo.app.core.extension.Plugin;
|
import run.halo.app.core.extension.Plugin;
|
||||||
import run.halo.app.extension.ExtensionClient;
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author guqing
|
* @author guqing
|
||||||
|
@ -22,10 +26,10 @@ public class PluginDevelopmentInitializer implements ApplicationListener<Applica
|
||||||
|
|
||||||
private final PluginProperties pluginProperties;
|
private final PluginProperties pluginProperties;
|
||||||
|
|
||||||
private final ExtensionClient extensionClient;
|
private final ReactiveExtensionClient extensionClient;
|
||||||
|
|
||||||
public PluginDevelopmentInitializer(HaloPluginManager haloPluginManager,
|
public PluginDevelopmentInitializer(HaloPluginManager haloPluginManager,
|
||||||
PluginProperties pluginProperties, ExtensionClient extensionClient) {
|
PluginProperties pluginProperties, ReactiveExtensionClient extensionClient) {
|
||||||
this.haloPluginManager = haloPluginManager;
|
this.haloPluginManager = haloPluginManager;
|
||||||
this.pluginProperties = pluginProperties;
|
this.pluginProperties = pluginProperties;
|
||||||
this.extensionClient = extensionClient;
|
this.extensionClient = extensionClient;
|
||||||
|
@ -41,19 +45,18 @@ public class PluginDevelopmentInitializer implements ApplicationListener<Applica
|
||||||
|
|
||||||
private void createFixedPluginIfNecessary(HaloPluginManager pluginManager) {
|
private void createFixedPluginIfNecessary(HaloPluginManager pluginManager) {
|
||||||
for (Path path : pluginProperties.getFixedPluginPath()) {
|
for (Path path : pluginProperties.getFixedPluginPath()) {
|
||||||
// already loaded
|
|
||||||
if (idForPath(path) != null) {
|
// Already loaded do not load again
|
||||||
continue;
|
String pluginId = idForPath(path);
|
||||||
}
|
|
||||||
|
|
||||||
// for issue #2901
|
// for issue #2901
|
||||||
String pluginId;
|
if (pluginId == null) {
|
||||||
|
try {
|
||||||
try {
|
pluginId = pluginManager.loadPlugin(path);
|
||||||
pluginId = pluginManager.loadPlugin(path);
|
} catch (Exception e) {
|
||||||
} catch (Exception e) {
|
log.warn(e.getMessage(), e);
|
||||||
log.warn(e.getMessage(), e);
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginId);
|
PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginId);
|
||||||
|
@ -62,10 +65,14 @@ public class PluginDevelopmentInitializer implements ApplicationListener<Applica
|
||||||
}
|
}
|
||||||
Plugin plugin = new YamlPluginFinder().find(pluginWrapper.getPluginPath());
|
Plugin plugin = new YamlPluginFinder().find(pluginWrapper.getPluginPath());
|
||||||
extensionClient.fetch(Plugin.class, plugin.getMetadata().getName())
|
extensionClient.fetch(Plugin.class, plugin.getMetadata().getName())
|
||||||
.ifPresentOrElse(persistent -> {
|
.flatMap(persistent -> {
|
||||||
plugin.getMetadata().setVersion(persistent.getMetadata().getVersion());
|
plugin.getMetadata().setVersion(persistent.getMetadata().getVersion());
|
||||||
extensionClient.update(plugin);
|
return extensionClient.update(plugin);
|
||||||
}, () -> extensionClient.create(plugin));
|
})
|
||||||
|
.switchIfEmpty(Mono.defer(() -> extensionClient.create(plugin)))
|
||||||
|
.retryWhen(Retry.backoff(10, Duration.ofMillis(100))
|
||||||
|
.filter(t -> t instanceof OptimisticLockingFailureException))
|
||||||
|
.block();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue