fix: plugin status check to prevent inconsistent status (#3235)

#### What type of PR is this?
/kind improvement
/area core
/milestone 2.3.x
#### What this PR does / why we need it:
当开发模式启动时上传 JAR 运行插件会出现插件不存在的异常,但由于 PluginReconciler 中检查状态不一致后 return 在 optional 语句中只是让当前 optional 后面的代码停止执行,还会继续执行 optional 外面的代码导致 status 的异常信息不一致,进而 object equals 始终为 false 而无法让 reconciler 终止运行导致循环。

此 PR 调整了一下代码位置,进入 reconciler 时先进行检查,如果不满足则不执行后面的代码同时将信息写入 plugin.status 让用户知晓。

此问题是修改了 Reconciler 判断逻辑后出现的 https://github.com/halo-dev/halo/pull/3210 ,因此不影响之前的代码只针对当前 2.3.x

#### Special notes for your reviewer:
how to test it?
1. 模拟一个插件找不到的错误场景例如以生产模式启动插件但配置 fixed-plugin 指定为插件项目目录
2. 启动 Halo 看 Reconciler 是否会一直在控制台输出日志
3. 卸载它能成功

/cc @halo-dev/sig-halo 
#### Does this PR introduce a user-facing change?

```release-note
None
```
pull/3236/head^2
guqing 2023-02-07 15:10:14 +08:00 committed by GitHub
parent df9b04c4d5
commit 6809dbb251
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 42 additions and 24 deletions

View File

@ -36,6 +36,7 @@ import run.halo.app.infra.utils.JsonUtils;
import run.halo.app.infra.utils.PathUtils;
import run.halo.app.plugin.HaloPluginManager;
import run.halo.app.plugin.PluginConst;
import run.halo.app.plugin.PluginNotFoundException;
import run.halo.app.plugin.PluginStartingError;
import run.halo.app.plugin.event.PluginCreatedEvent;
import run.halo.app.plugin.resources.BundleResourceUtils;
@ -82,24 +83,13 @@ public class PluginReconciler implements Reconciler<Request> {
ensurePluginLoaded();
}
if (!checkPluginState(name)) {
return;
}
client.fetch(Plugin.class, name).ifPresent(plugin -> {
Plugin oldPlugin = JsonUtils.deepCopy(plugin);
Plugin.PluginStatus pluginStatus = plugin.statusNonNull();
PluginWrapper pluginWrapper = haloPluginManager.getPlugin(name);
if (pluginWrapper == null) {
pluginStatus.setPhase(PluginState.FAILED);
pluginStatus.setReason("PluginNotFound");
pluginStatus.setMessage("Plugin " + name + " not found in plugin manager");
} else {
// Set to the correct state
pluginStatus.setPhase(pluginWrapper.getPluginState());
if (haloPluginManager.getUnresolvedPlugins().contains(pluginWrapper)) {
// load and resolve plugin
haloPluginManager.loadPlugin(pluginWrapper.getPluginPath());
}
}
String logo = plugin.getSpec().getLogo();
if (PathUtils.isAbsoluteUri(logo)) {
pluginStatus.setLogo(logo);
@ -119,6 +109,36 @@ public class PluginReconciler implements Reconciler<Request> {
stopPlugin(name);
}
private boolean checkPluginState(String name) {
// check plugin state
return client.fetch(Plugin.class, name)
.map(plugin -> {
Plugin oldPlugin = JsonUtils.deepCopy(plugin);
Plugin.PluginStatus pluginStatus = plugin.statusNonNull();
PluginWrapper pluginWrapper = haloPluginManager.getPlugin(name);
if (pluginWrapper == null) {
pluginStatus.setPhase(PluginState.FAILED);
pluginStatus.setReason("PluginNotFound");
pluginStatus.setMessage(
"Plugin " + plugin.getMetadata().getName()
+ " not found in plugin manager.");
if (!plugin.equals(oldPlugin)) {
client.update(plugin);
}
return false;
}
// Set to the correct state
pluginStatus.setPhase(pluginWrapper.getPluginState());
if (haloPluginManager.getUnresolvedPlugins().contains(pluginWrapper)) {
// load and resolve plugin
haloPluginManager.loadPlugin(pluginWrapper.getPluginPath());
}
return true;
})
.orElse(false);
}
private void ensurePluginLoaded() {
// load plugin if exists in plugin root paths.
List<PluginWrapper> loadedPlugins = haloPluginManager.getPlugins();
@ -172,20 +192,15 @@ public class PluginReconciler implements Reconciler<Request> {
private boolean verifyStartCondition(String pluginName) {
PluginWrapper pluginWrapper = haloPluginManager.getPlugin(pluginName);
if (pluginWrapper == null) {
throw new PluginNotFoundException(
"Plugin " + pluginName + " not found in plugin manager.");
}
return client.fetch(Plugin.class, pluginName).map(plugin -> {
Plugin.PluginStatus oldStatus = JsonUtils.deepCopy(plugin.statusNonNull());
Plugin.PluginStatus status = plugin.statusNonNull();
status.setLastTransitionTime(Instant.now());
if (pluginWrapper == null) {
status.setPhase(PluginState.FAILED);
status.setReason("PluginNotFound");
status.setMessage("Plugin [" + pluginName + "] not found in plugin manager");
if (!oldStatus.equals(status)) {
client.update(plugin);
}
return false;
}
// Check if this plugin version is match requires param.
if (!haloPluginManager.validatePluginVersion(pluginWrapper)) {
@ -206,6 +221,9 @@ public class PluginReconciler implements Reconciler<Request> {
status.setPhase(pluginState);
status.setReason("PluginDisabled");
status.setMessage("The plugin is disabled for some reason and cannot be started.");
if (!oldStatus.equals(status)) {
client.update(plugin);
}
}
return true;
}).orElse(false);