(control) GUI for triggering control-side actors
This commit is contained in:
parent
4155fbe94c
commit
67a1e1c874
@ -3,9 +3,9 @@ package nu.marginalia.control;
|
||||
import spark.ResponseTransformer;
|
||||
|
||||
public class Redirects {
|
||||
public static final HtmlRedirect redirectToActors = new HtmlRedirect("/actors");
|
||||
public static final HtmlRedirect redirectToApiKeys = new HtmlRedirect("/api-keys");
|
||||
public static final HtmlRedirect redirectToStorage = new HtmlRedirect("/storage");
|
||||
public static final HtmlRedirect redirectToOverview = new HtmlRedirect("/");
|
||||
public static final HtmlRedirect redirectToBlacklist = new HtmlRedirect("/blacklist");
|
||||
public static final HtmlRedirect redirectToComplaints = new HtmlRedirect("/complaints");
|
||||
public static final HtmlRedirect redirectToMessageQueue = new HtmlRedirect("/message-queue");
|
||||
|
@ -1,12 +1,16 @@
|
||||
package nu.marginalia.control.sys.svc;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import lombok.SneakyThrows;
|
||||
import nu.marginalia.client.Context;
|
||||
import nu.marginalia.control.Redirects;
|
||||
import nu.marginalia.control.actor.ControlActor;
|
||||
import nu.marginalia.control.actor.ControlActorService;
|
||||
import nu.marginalia.db.DomainTypes;
|
||||
import nu.marginalia.executor.client.ExecutorClient;
|
||||
import nu.marginalia.mq.MessageQueueFactory;
|
||||
import nu.marginalia.mq.outbox.MqOutbox;
|
||||
import nu.marginalia.renderer.RendererFactory;
|
||||
import nu.marginalia.service.control.ServiceEventLog;
|
||||
import nu.marginalia.service.id.ServiceId;
|
||||
import spark.Request;
|
||||
@ -19,13 +23,23 @@ public class ControlSysActionsService {
|
||||
private final MqOutbox apiOutbox;
|
||||
private final DomainTypes domainTypes;
|
||||
private final ServiceEventLog eventLog;
|
||||
private final RendererFactory rendererFactory;
|
||||
private final ControlActorService controlActorService;
|
||||
private final ExecutorClient executorClient;
|
||||
|
||||
@Inject
|
||||
public ControlSysActionsService(MessageQueueFactory mqFactory, DomainTypes domainTypes, ServiceEventLog eventLog, ExecutorClient executorClient) {
|
||||
public ControlSysActionsService(MessageQueueFactory mqFactory,
|
||||
DomainTypes domainTypes,
|
||||
ServiceEventLog eventLog,
|
||||
RendererFactory rendererFactory,
|
||||
ControlActorService controlActorService,
|
||||
ExecutorClient executorClient)
|
||||
{
|
||||
this.apiOutbox = createApiOutbox(mqFactory);
|
||||
this.eventLog = eventLog;
|
||||
this.domainTypes = domainTypes;
|
||||
this.rendererFactory = rendererFactory;
|
||||
this.controlActorService = controlActorService;
|
||||
this.executorClient = executorClient;
|
||||
}
|
||||
|
||||
@ -38,12 +52,17 @@ public class ControlSysActionsService {
|
||||
return mqFactory.createOutbox(inboxName, 0, outboxName, 0, UUID.randomUUID());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void register() {
|
||||
Spark.post("/public/actions/flush-api-caches", this::flushApiCaches, Redirects.redirectToActors);
|
||||
Spark.post("/public/actions/reload-blogs-list", this::reloadBlogsList, Redirects.redirectToActors);
|
||||
Spark.post("/public/actions/calculate-adjacencies", this::calculateAdjacencies, Redirects.redirectToActors);
|
||||
Spark.post("/public/actions/truncate-links-database", this::truncateLinkDatabase, Redirects.redirectToActors);
|
||||
Spark.post("/public/actions/trigger-data-exports", this::triggerDataExports, Redirects.redirectToActors);
|
||||
var actionsView = rendererFactory.renderer("control/sys/sys-actions");
|
||||
|
||||
Spark.get("/public/actions", (rq,rsp) -> new Object(), actionsView::render);
|
||||
Spark.post("/public/actions/recalculate-adjacencies-graph", this::calculateAdjacencies, Redirects.redirectToOverview);
|
||||
Spark.post("/public/actions/reindex-all", this::reindexAll, Redirects.redirectToOverview);
|
||||
Spark.post("/public/actions/reprocess-all", this::reprocessAll, 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);
|
||||
}
|
||||
|
||||
public Object triggerDataExports(Request request, Response response) throws Exception {
|
||||
@ -54,23 +73,6 @@ public class ControlSysActionsService {
|
||||
return "";
|
||||
}
|
||||
|
||||
public Object truncateLinkDatabase(Request request, Response response) throws Exception {
|
||||
|
||||
String footgunLicense = request.queryParams("footgun-license");
|
||||
|
||||
if (!"YES".equals(footgunLicense)) {
|
||||
Spark.halt(403);
|
||||
return "You must agree to the footgun license to truncate the link database";
|
||||
}
|
||||
|
||||
eventLog.logEvent("USER-ACTION", "FLUSH-LINK-DATABASE");
|
||||
|
||||
// FIXME:
|
||||
// actors.start(Actor.TRUNCATE_LINK_DATABASE);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public Object reloadBlogsList(Request request, Response response) throws Exception {
|
||||
eventLog.logEvent("USER-ACTION", "RELOAD-BLOGS-LIST");
|
||||
|
||||
@ -89,10 +91,26 @@ public class ControlSysActionsService {
|
||||
public Object calculateAdjacencies(Request request, Response response) throws Exception {
|
||||
eventLog.logEvent("USER-ACTION", "CALCULATE-ADJACENCIES");
|
||||
|
||||
// This is technically not a partitioned operation, but we execute it at node zero
|
||||
// This is technically not a partitioned operation, but we execute it at node 1
|
||||
// and let the effects be global :-)
|
||||
|
||||
executorClient.calculateAdjacencies(Context.fromRequest(request), 0);
|
||||
executorClient.calculateAdjacencies(Context.fromRequest(request), 1);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public Object reindexAll(Request request, Response response) throws Exception {
|
||||
eventLog.logEvent("USER-ACTION", "REINDEX-ALL");
|
||||
|
||||
controlActorService.start(ControlActor.REINDEX_ALL);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public Object reprocessAll(Request request, Response response) throws Exception {
|
||||
eventLog.logEvent("USER-ACTION", "REPROCESS-ALL");
|
||||
|
||||
controlActorService.start(ControlActor.REPROCESS_ALL);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
@ -14,6 +14,11 @@
|
||||
{{/unless}}
|
||||
|
||||
{{#if nodes}}
|
||||
<div class="my-3 p-3 border bg-light">
|
||||
Index nodes are processing units. The search engine requires at least one, but more can be added
|
||||
to spread the system load across multiple physical disks or even multiple servers.
|
||||
</div>
|
||||
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Node ID</th>
|
||||
@ -28,14 +33,6 @@
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
|
||||
<div class="m-5 p-5 border bg-light">
|
||||
<h2 class="my-3">Index Nodes</h2>
|
||||
<p>
|
||||
Index nodes are processing units. The search engine requires at least one, but more can be added
|
||||
to spread the system load across multiple physical disks or even multiple servers.
|
||||
</p>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
|
@ -21,6 +21,7 @@
|
||||
<li class="nav-item dropdown">
|
||||
<a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" role="button" aria-expanded="false">System</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="/actions" title="System actions">Actions</a></li>
|
||||
<li><a class="dropdown-item" href="/nodes" title="View and configure index nodes">Nodes</a></li>
|
||||
<li><a class="dropdown-item" href="/datasets" title="View and update the data sets">Datasets</a></li>
|
||||
<li><a class="dropdown-item" href="/events" title="View the event log">Events</a></li>
|
||||
|
@ -0,0 +1,102 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
{{> control/partials/head-includes }}
|
||||
<head><title>Control Service: Actions</title></head>
|
||||
<body>
|
||||
{{> control/partials/nav}}
|
||||
|
||||
<div class="container">
|
||||
<h1 class="my-3">System Actions</h1>
|
||||
|
||||
<div class="my-3 border p-3 bg-light">
|
||||
These are actions that perform system-wide operations,
|
||||
on each node in the system. Nodes are included if they are
|
||||
configured to be part of the <em>precession</em> in the Node Configuration.
|
||||
For a single-node system, most of these actions may be triggered from the
|
||||
single node's actions tab.
|
||||
</div>
|
||||
|
||||
<div class="accordion mt-3" id="accordionActions">
|
||||
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseCalculateAdjacencies"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapseCalculateAdjacencies">
|
||||
Calculate Adjacencies
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseCalculateAdjacencies" class="accordion-collapse collapse p-3" data-bs-parent="#accordionActions">
|
||||
<div class="mb-3">
|
||||
This will re-calculate the adjacencies graph. The adjacencies graph is used to calculate the domain ranking.
|
||||
</div>
|
||||
<form method="post" action="actions/recalculate-adjacencies-graph">
|
||||
<button
|
||||
class="btn btn-primary me-md-2"
|
||||
onclick="return confirm('Confirm recalculation of adjacencies graph');"
|
||||
type="submit">
|
||||
Recalculate Graph</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseReindexAll"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapseReindexAll">
|
||||
Recalculate Rankings
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseReindexAll" class="accordion-collapse collapse p-3" data-bs-parent="#accordionActions">
|
||||
<div class="mb-3">
|
||||
This will successively re-calculate the domain rankings for all nodes configured to be part in the precession,
|
||||
and then re-construct the indexes from existing journal data.
|
||||
</div>
|
||||
<form method="post" action="actions/reindex-all">
|
||||
<button
|
||||
class="btn btn-primary me-md-2"
|
||||
onclick="return confirm('Confirm reindexing of all nodes');"
|
||||
type="submit">
|
||||
Reconstruct Indexes</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseReprocessAll"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapseReprocessAll">
|
||||
Reprocess Data
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseReprocessAll" class="accordion-collapse collapse p-3" data-bs-parent="#accordionActions">
|
||||
<div class="mb-3">
|
||||
This will reprocess the crawl data on each node configured to be part in the precession, based on
|
||||
the currently ACTIVE crawl data. If no crawl data is ACTIVE, the node will be omitted.
|
||||
</div>
|
||||
<form method="post" action="actions/reprocess-all">
|
||||
<button
|
||||
class="btn btn-primary me-md-2"
|
||||
onclick="return confirm('Confirm reprocessing');"
|
||||
type="submit">
|
||||
Reprocess Crawl Data</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
{{> control/partials/foot-includes }}
|
||||
</html>
|
@ -69,7 +69,7 @@ public class ProcessingService {
|
||||
}
|
||||
|
||||
public Object startAdjacencyCalculation(Request request, Response response) throws Exception {
|
||||
actorControlService.start(ExecutorActor.ADJACENCY_CALCULATION);
|
||||
actorControlService.startFrom(ExecutorActor.ADJACENCY_CALCULATION, new TriggerAdjacencyCalculationActor.Run());
|
||||
return "";
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user