(control) UX fixes, node GUI doesn't break when an executor service goes offline.
This commit is contained in:
parent
c0fb9e17e8
commit
8dea7217a6
@ -1,8 +1,10 @@
|
||||
package nu.marginalia.executor.client;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import nu.marginalia.client.AbstractDynamicClient;
|
||||
import nu.marginalia.client.Context;
|
||||
import nu.marginalia.client.exception.RouteNotConfiguredException;
|
||||
import nu.marginalia.executor.model.ActorRunStates;
|
||||
import nu.marginalia.executor.model.load.LoadParameters;
|
||||
import nu.marginalia.executor.model.transfer.TransferItem;
|
||||
@ -18,6 +20,8 @@ import java.io.OutputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ExecutorClient extends AbstractDynamicClient {
|
||||
@ -63,11 +67,6 @@ public class ExecutorClient extends AbstractDynamicClient {
|
||||
post(ctx, node, "/process/adjacency-calculation", "").blockingSubscribe();
|
||||
}
|
||||
|
||||
public void exportData(Context ctx) {
|
||||
// post(ctx, node, "/process/adjacency-calculation/", "").blockingSubscribe();
|
||||
// FIXME this shouldn't be done in the executor
|
||||
}
|
||||
|
||||
public void sideloadEncyclopedia(Context ctx, int node, Path sourcePath, String baseUrl) {
|
||||
post(ctx, node,
|
||||
"/sideload/encyclopedia?path="+ URLEncoder.encode(sourcePath.toString(), StandardCharsets.UTF_8) + "&baseUrl=" + URLEncoder.encode(baseUrl, StandardCharsets.UTF_8),
|
||||
@ -110,15 +109,33 @@ public class ExecutorClient extends AbstractDynamicClient {
|
||||
}
|
||||
|
||||
public ActorRunStates getActorStates(Context context, int node) {
|
||||
return get(context, node, "/actor", ActorRunStates.class).blockingFirst();
|
||||
try {
|
||||
return get(context, node, "/actor", ActorRunStates.class).blockingFirst();
|
||||
}
|
||||
catch (RouteNotConfiguredException ex) {
|
||||
// node is down, return dummy data
|
||||
return new ActorRunStates(node, new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
public UploadDirContents listSideloadDir(Context context, int node) {
|
||||
return get(context, node, "/sideload/", UploadDirContents.class).blockingFirst();
|
||||
try {
|
||||
return get(context, node, "/sideload/", UploadDirContents.class).blockingFirst();
|
||||
}
|
||||
catch (RouteNotConfiguredException ex) {
|
||||
// node is down, return dummy data
|
||||
return new UploadDirContents("/", new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
public FileStorageContent listFileStorage(Context context, int node, FileStorageId fileId) {
|
||||
return get(context, node, "/storage/"+fileId.id(), FileStorageContent.class).blockingFirst();
|
||||
try {
|
||||
return get(context, node, "/storage/"+fileId.id(), FileStorageContent.class).blockingFirst();
|
||||
}
|
||||
catch (RouteNotConfiguredException ex) {
|
||||
// node is down, return dummy data
|
||||
return new FileStorageContent(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
public void transferFile(Context context, int node, FileStorageId fileId, String path, OutputStream destOutputStream) {
|
||||
|
@ -9,4 +9,7 @@ public record NodeConfiguration(int node,
|
||||
boolean disabled
|
||||
)
|
||||
{
|
||||
public int getId() {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
package nu.marginalia.control.node.model;
|
||||
|
||||
public record IndexNode(int id) {
|
||||
}
|
@ -183,7 +183,7 @@ public class ControlNodeService {
|
||||
|
||||
return Map.of(
|
||||
"tab", Map.of("storage", true),
|
||||
"node", new IndexNode(nodeId),
|
||||
"node", nodeConfigurationService.get(nodeId),
|
||||
"view", Map.of("specs", true)
|
||||
);
|
||||
}
|
||||
@ -193,7 +193,7 @@ public class ControlNodeService {
|
||||
|
||||
return Map.of(
|
||||
"tab", Map.of("actors", true),
|
||||
"node", new IndexNode(nodeId),
|
||||
"node", nodeConfigurationService.get(nodeId),
|
||||
"actors", executorClient.getActorStates(Context.fromRequest(request), nodeId).states()
|
||||
);
|
||||
}
|
||||
@ -203,7 +203,7 @@ public class ControlNodeService {
|
||||
|
||||
return Map.of(
|
||||
"tab", Map.of("actions", true),
|
||||
"node", new IndexNode(nodeId),
|
||||
"node", nodeConfigurationService.get(nodeId),
|
||||
"view", Map.of(request.queryParams("view"), true),
|
||||
"uploadDirContents", executorClient.listSideloadDir(Context.fromRequest(request), nodeId),
|
||||
"allBackups",
|
||||
@ -223,7 +223,7 @@ public class ControlNodeService {
|
||||
return Map.of(
|
||||
"tab", Map.of("storage", true),
|
||||
"view", Map.of("conf", true),
|
||||
"node", new IndexNode(nodeId),
|
||||
"node", nodeConfigurationService.get(nodeId),
|
||||
"storagebase", getStorageBaseList(nodeId)
|
||||
);
|
||||
}
|
||||
@ -245,7 +245,7 @@ public class ControlNodeService {
|
||||
return Map.of(
|
||||
"tab", Map.of("storage", true),
|
||||
"view", Map.of(view, true),
|
||||
"node", new IndexNode(nodeId),
|
||||
"node", nodeConfigurationService.get(nodeId),
|
||||
"storage", makeFileStorageBaseWithStorage(getFileStorageIds(type, nodeId))
|
||||
);
|
||||
}
|
||||
@ -266,7 +266,7 @@ public class ControlNodeService {
|
||||
return Map.of(
|
||||
"tab", Map.of("storage", true),
|
||||
"view", Map.of(view, true),
|
||||
"node", new IndexNode(nodeId),
|
||||
"node", nodeConfigurationService.get(nodeId),
|
||||
"storage", storage
|
||||
);
|
||||
}
|
||||
@ -284,7 +284,7 @@ public class ControlNodeService {
|
||||
|
||||
return Map.of(
|
||||
"tab", Map.of("config", true),
|
||||
"node", new IndexNode(nodeId),
|
||||
"node", nodeConfigurationService.get(nodeId),
|
||||
"config", Objects.requireNonNull(nodeConfigurationService.get(nodeId), "Failed to fetch configuration"),
|
||||
"storage", storage);
|
||||
}
|
||||
@ -325,7 +325,7 @@ public class ControlNodeService {
|
||||
actors.removeIf(actor -> actor.state().equals("MONITOR"));
|
||||
|
||||
return Map.of(
|
||||
"node", new IndexNode(nodeId),
|
||||
"node", nodeConfigurationService.get(nodeId),
|
||||
"status", getStatus(config),
|
||||
"events", getEvents(nodeId),
|
||||
"processes", heartbeatService.getProcessHeartbeatsForNode(nodeId),
|
||||
|
@ -72,7 +72,6 @@ public class ControlSysActionsService {
|
||||
Spark.post("/public/actions/recrawl-all", this::recrawlAll, Redirects.redirectToOverview);
|
||||
Spark.post("/public/actions/flush-api-caches", this::flushApiCaches, Redirects.redirectToOverview);
|
||||
Spark.post("/public/actions/reload-blogs-list", this::reloadBlogsList, Redirects.redirectToOverview);
|
||||
Spark.post("/public/actions/trigger-data-exports", this::triggerDataExports, Redirects.redirectToOverview);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@ -99,14 +98,6 @@ public class ControlSysActionsService {
|
||||
return Map.of("precessionNodes", eligibleNodes);
|
||||
}
|
||||
|
||||
public Object triggerDataExports(Request request, Response response) throws Exception {
|
||||
eventLog.logEvent("USER-ACTION", "EXPORT-DATA");
|
||||
|
||||
executorClient.exportData(Context.fromRequest(request));
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public Object reloadBlogsList(Request request, Response response) throws Exception {
|
||||
eventLog.logEvent("USER-ACTION", "RELOAD-BLOGS-LIST");
|
||||
|
||||
|
@ -10,8 +10,8 @@
|
||||
This will perform a new crawl on node {{node.id}} based on the crawl spec you select below.
|
||||
Additional specifications can be created <a href="/nodes/{{node.id}}/storage/new-specs">with this form</a>.
|
||||
</div>
|
||||
<div class="my-3 p-3 border text-danger">
|
||||
<p><strong>IMPORTANT!</strong> Be sure you've read and understood the
|
||||
<div class="my-3 p-3 border">
|
||||
<p><em class="text-danger">IMPORTANT!</em> Be sure you've read and understood the
|
||||
<a href="https://github.com/MarginaliaSearch/MarginaliaSearch/blob/master/doc/crawling.md">crawling documentation</a>
|
||||
before you begin a crawl. You will be accessing real servers from your connection, and you may end up on IP greylists
|
||||
that temporarily block your access to those servers for up to a few weeks; on rare occasions permanently. The crawler
|
||||
|
@ -1,5 +1,11 @@
|
||||
|
||||
<h1 class="my-3">Index Node {{node.id}}</h1>
|
||||
{{#if node.disabled}}
|
||||
<small class="text-danger">This index node is disabled!</small>
|
||||
{{/if}}
|
||||
{{#unless node.acceptQueries}}
|
||||
<small class="text-danger">This index node is not accepting queries!</small>
|
||||
{{/unless}}
|
||||
<nav class="nav nav-tabs">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if tab.overview}}active{{/if}}" href="/nodes/{{node.id}}/">Overview</a>
|
||||
@ -30,4 +36,4 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if tab.config}}active{{/if}}" href="/nodes/{{node.id}}/configuration">Configuration</a>
|
||||
</li>
|
||||
</nav>
|
||||
</nav>
|
||||
|
Loading…
Reference in New Issue
Block a user