diff --git a/code/common/config/java/nu/marginalia/nodecfg/NodeConfigurationService.java b/code/common/config/java/nu/marginalia/nodecfg/NodeConfigurationService.java index d69d87fc..7098a298 100644 --- a/code/common/config/java/nu/marginalia/nodecfg/NodeConfigurationService.java +++ b/code/common/config/java/nu/marginalia/nodecfg/NodeConfigurationService.java @@ -3,6 +3,7 @@ package nu.marginalia.nodecfg; import com.google.inject.Inject; import com.zaxxer.hikari.HikariDataSource; import nu.marginalia.nodecfg.model.NodeConfiguration; +import nu.marginalia.nodecfg.model.NodeProfile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,10 +21,10 @@ public class NodeConfigurationService { this.dataSource = dataSource; } - public NodeConfiguration create(int id, String description, boolean acceptQueries, boolean keepWarcs) throws SQLException { + public NodeConfiguration create(int id, String description, boolean acceptQueries, boolean keepWarcs, NodeProfile nodeProfile) throws SQLException { try (var conn = dataSource.getConnection(); var is = conn.prepareStatement(""" - INSERT IGNORE INTO NODE_CONFIGURATION(ID, DESCRIPTION, ACCEPT_QUERIES, KEEP_WARCS) VALUES(?, ?, ?, ?) + INSERT IGNORE INTO NODE_CONFIGURATION(ID, DESCRIPTION, ACCEPT_QUERIES, KEEP_WARCS, NODE_PROFILE) VALUES(?, ?, ?, ?, ?) """) ) { @@ -31,6 +32,7 @@ public class NodeConfigurationService { is.setString(2, description); is.setBoolean(3, acceptQueries); is.setBoolean(4, keepWarcs); + is.setString(5, nodeProfile.name()); if (is.executeUpdate() <= 0) { throw new IllegalStateException("Failed to insert configuration"); @@ -43,7 +45,7 @@ public class NodeConfigurationService { public List getAll() { try (var conn = dataSource.getConnection(); var qs = conn.prepareStatement(""" - SELECT ID, DESCRIPTION, ACCEPT_QUERIES, AUTO_CLEAN, PRECESSION, KEEP_WARCS, DISABLED + SELECT ID, DESCRIPTION, ACCEPT_QUERIES, AUTO_CLEAN, PRECESSION, KEEP_WARCS, NODE_PROFILE, DISABLED FROM NODE_CONFIGURATION """)) { var rs = qs.executeQuery(); @@ -58,6 +60,7 @@ public class NodeConfigurationService { rs.getBoolean("AUTO_CLEAN"), rs.getBoolean("PRECESSION"), rs.getBoolean("KEEP_WARCS"), + NodeProfile.valueOf(rs.getString("NODE_PROFILE")), rs.getBoolean("DISABLED") )); } @@ -72,7 +75,7 @@ public class NodeConfigurationService { public NodeConfiguration get(int nodeId) throws SQLException { try (var conn = dataSource.getConnection(); var qs = conn.prepareStatement(""" - SELECT ID, DESCRIPTION, ACCEPT_QUERIES, AUTO_CLEAN, PRECESSION, KEEP_WARCS, DISABLED + SELECT ID, DESCRIPTION, ACCEPT_QUERIES, AUTO_CLEAN, PRECESSION, KEEP_WARCS, NODE_PROFILE, DISABLED FROM NODE_CONFIGURATION WHERE ID=? """)) { @@ -86,6 +89,7 @@ public class NodeConfigurationService { rs.getBoolean("AUTO_CLEAN"), rs.getBoolean("PRECESSION"), rs.getBoolean("KEEP_WARCS"), + NodeProfile.valueOf(rs.getString("NODE_PROFILE")), rs.getBoolean("DISABLED") ); } @@ -98,7 +102,7 @@ public class NodeConfigurationService { try (var conn = dataSource.getConnection(); var us = conn.prepareStatement(""" UPDATE NODE_CONFIGURATION - SET DESCRIPTION=?, ACCEPT_QUERIES=?, AUTO_CLEAN=?, PRECESSION=?, KEEP_WARCS=?, DISABLED=? + SET DESCRIPTION=?, ACCEPT_QUERIES=?, AUTO_CLEAN=?, PRECESSION=?, KEEP_WARCS=?, DISABLED=?, NODE_PROFILE=? WHERE ID=? """)) { @@ -108,7 +112,8 @@ public class NodeConfigurationService { us.setBoolean(4, config.includeInPrecession()); us.setBoolean(5, config.keepWarcs()); us.setBoolean(6, config.disabled()); - us.setInt(7, config.node()); + us.setString(7, config.profile().name()); + us.setInt(8, config.node()); if (us.executeUpdate() <= 0) throw new IllegalStateException("Failed to update configuration"); diff --git a/code/common/config/java/nu/marginalia/nodecfg/model/NodeConfiguration.java b/code/common/config/java/nu/marginalia/nodecfg/model/NodeConfiguration.java index fb7c7aba..35a71b98 100644 --- a/code/common/config/java/nu/marginalia/nodecfg/model/NodeConfiguration.java +++ b/code/common/config/java/nu/marginalia/nodecfg/model/NodeConfiguration.java @@ -6,6 +6,7 @@ public record NodeConfiguration(int node, boolean autoClean, boolean includeInPrecession, boolean keepWarcs, + NodeProfile profile, boolean disabled ) { diff --git a/code/common/config/java/nu/marginalia/nodecfg/model/NodeProfile.java b/code/common/config/java/nu/marginalia/nodecfg/model/NodeProfile.java new file mode 100644 index 00000000..96e7c24b --- /dev/null +++ b/code/common/config/java/nu/marginalia/nodecfg/model/NodeProfile.java @@ -0,0 +1,28 @@ +package nu.marginalia.nodecfg.model; + +public enum NodeProfile { + BATCH_CRAWL, + REALTIME, + MIXED, + SIDELOAD; + + public boolean isBatchCrawl() { + return this == BATCH_CRAWL; + } + public boolean isRealtime() { + return this == REALTIME; + } + public boolean isMixed() { + return this == MIXED; + } + public boolean isSideload() { + return this == SIDELOAD; + } + + public boolean permitBatchCrawl() { + return isBatchCrawl() ||isMixed(); + } + public boolean permitSideload() { + return isMixed() || isSideload(); + } +} diff --git a/code/common/db/resources/db/migration/V24_11_0_001__add_node_profile.sql b/code/common/db/resources/db/migration/V24_11_0_001__add_node_profile.sql new file mode 100644 index 00000000..914fcaef --- /dev/null +++ b/code/common/db/resources/db/migration/V24_11_0_001__add_node_profile.sql @@ -0,0 +1 @@ +ALTER TABLE WMSA_prod.NODE_CONFIGURATION ADD COLUMN NODE_PROFILE VARCHAR(255) DEFAULT 'MIXED'; \ No newline at end of file diff --git a/code/common/service/java/nu/marginalia/service/server/NodeStatusWatcher.java b/code/common/service/java/nu/marginalia/service/server/NodeStatusWatcher.java index 920de3db..23c99020 100644 --- a/code/common/service/java/nu/marginalia/service/server/NodeStatusWatcher.java +++ b/code/common/service/java/nu/marginalia/service/server/NodeStatusWatcher.java @@ -4,6 +4,7 @@ import com.google.inject.Inject; import com.google.inject.name.Named; import nu.marginalia.mq.persistence.MqPersistence; import nu.marginalia.nodecfg.NodeConfigurationService; +import nu.marginalia.nodecfg.model.NodeProfile; import nu.marginalia.storage.FileStorageService; import nu.marginalia.storage.model.FileStorageBaseType; import org.slf4j.Logger; @@ -56,7 +57,9 @@ public class NodeStatusWatcher { private void setupNode() { try { - configurationService.create(nodeId, "Node " + nodeId, true, false); + NodeProfile profile = NodeProfile.MIXED; + + configurationService.create(nodeId, "Node " + nodeId, true, false, profile); fileStorageService.createStorageBase("Index Data", Path.of("/idx"), nodeId, FileStorageBaseType.CURRENT); fileStorageService.createStorageBase("Index Backups", Path.of("/backup"), nodeId, FileStorageBaseType.BACKUP); diff --git a/code/execution/api/java/nu/marginalia/executor/client/ExecutorClient.java b/code/execution/api/java/nu/marginalia/executor/client/ExecutorClient.java index 020c29b0..5670c827 100644 --- a/code/execution/api/java/nu/marginalia/executor/client/ExecutorClient.java +++ b/code/execution/api/java/nu/marginalia/executor/client/ExecutorClient.java @@ -182,4 +182,10 @@ public class ExecutorClient { } } + public void restartExecutorService(int node) { + channelPool.call(ExecutorApiBlockingStub::restartExecutorService) + .forNode(node) + .run(Empty.getDefaultInstance()); + } + } diff --git a/code/execution/api/src/main/protobuf/executor-api.proto b/code/execution/api/src/main/protobuf/executor-api.proto index 667fe70d..b3ab1d41 100644 --- a/code/execution/api/src/main/protobuf/executor-api.proto +++ b/code/execution/api/src/main/protobuf/executor-api.proto @@ -17,6 +17,8 @@ service ExecutorApi { rpc downloadSampleData(RpcDownloadSampleData) returns (Empty) {} rpc calculateAdjacencies(Empty) returns (Empty) {} rpc restoreBackup(RpcFileStorageId) returns (Empty) {} + + rpc restartExecutorService(Empty) returns (Empty) {} } service ExecutorCrawlApi { diff --git a/code/execution/java/nu/marginalia/actor/ExecutorActor.java b/code/execution/java/nu/marginalia/actor/ExecutorActor.java index 3fe1c92f..bcb9d904 100644 --- a/code/execution/java/nu/marginalia/actor/ExecutorActor.java +++ b/code/execution/java/nu/marginalia/actor/ExecutorActor.java @@ -1,31 +1,37 @@ package nu.marginalia.actor; +import nu.marginalia.nodecfg.model.NodeProfile; + +import java.util.Set; + public enum ExecutorActor { - CRAWL, - LIVE_CRAWL, - RECRAWL, - RECRAWL_SINGLE_DOMAIN, - CONVERT_AND_LOAD, - PROC_CONVERTER_SPAWNER, - PROC_LOADER_SPAWNER, - PROC_CRAWLER_SPAWNER, - PROC_LIVE_CRAWL_SPAWNER, - MONITOR_PROCESS_LIVENESS, - MONITOR_FILE_STORAGE, - ADJACENCY_CALCULATION, - CRAWL_JOB_EXTRACTOR, - EXPORT_DATA, - EXPORT_SEGMENTATION_MODEL, - EXPORT_ATAGS, - EXPORT_TERM_FREQUENCIES, - EXPORT_FEEDS, - PROC_INDEX_CONSTRUCTOR_SPAWNER, - CONVERT, - RESTORE_BACKUP, - EXPORT_SAMPLE_DATA, - DOWNLOAD_SAMPLE, - SCRAPE_FEEDS, - UPDATE_RSS; + CRAWL(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + RECRAWL(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + RECRAWL_SINGLE_DOMAIN(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + PROC_CONVERTER_SPAWNER(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + PROC_CRAWLER_SPAWNER(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + ADJACENCY_CALCULATION(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + EXPORT_DATA(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + EXPORT_SEGMENTATION_MODEL(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + EXPORT_ATAGS(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + EXPORT_TERM_FREQUENCIES(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + EXPORT_FEEDS(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + EXPORT_SAMPLE_DATA(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + DOWNLOAD_SAMPLE(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED), + + PROC_LOADER_SPAWNER(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED, NodeProfile.SIDELOAD), + RESTORE_BACKUP(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED, NodeProfile.SIDELOAD), + CONVERT(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED, NodeProfile.SIDELOAD), + + CONVERT_AND_LOAD(NodeProfile.BATCH_CRAWL, NodeProfile.MIXED, NodeProfile.REALTIME, NodeProfile.SIDELOAD), + MONITOR_PROCESS_LIVENESS(NodeProfile.BATCH_CRAWL, NodeProfile.REALTIME, NodeProfile.MIXED, NodeProfile.SIDELOAD), + MONITOR_FILE_STORAGE(NodeProfile.BATCH_CRAWL, NodeProfile.REALTIME, NodeProfile.MIXED, NodeProfile.SIDELOAD), + PROC_INDEX_CONSTRUCTOR_SPAWNER(NodeProfile.BATCH_CRAWL, NodeProfile.REALTIME, NodeProfile.MIXED, NodeProfile.SIDELOAD), + + LIVE_CRAWL(NodeProfile.REALTIME), + PROC_LIVE_CRAWL_SPAWNER(NodeProfile.REALTIME), + SCRAPE_FEEDS(NodeProfile.REALTIME), + UPDATE_RSS(NodeProfile.REALTIME); public String id() { return "fsm:" + name().toLowerCase(); @@ -35,4 +41,9 @@ public enum ExecutorActor { return "fsm:" + name().toLowerCase() + ":" + node; } + ExecutorActor(NodeProfile... profileSet) { + this.profileSet = Set.of(profileSet); + } + + public Set profileSet; } diff --git a/code/execution/java/nu/marginalia/actor/ExecutorActorControlService.java b/code/execution/java/nu/marginalia/actor/ExecutorActorControlService.java index e5a6fc5a..e93b93b5 100644 --- a/code/execution/java/nu/marginalia/actor/ExecutorActorControlService.java +++ b/code/execution/java/nu/marginalia/actor/ExecutorActorControlService.java @@ -10,11 +10,14 @@ import nu.marginalia.actor.state.ActorStateInstance; import nu.marginalia.actor.state.ActorStep; import nu.marginalia.actor.task.*; import nu.marginalia.mq.MessageQueueFactory; +import nu.marginalia.nodecfg.NodeConfigurationService; +import nu.marginalia.nodecfg.model.NodeConfiguration; import nu.marginalia.service.control.ServiceEventLog; import nu.marginalia.service.server.BaseServiceParams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -28,10 +31,13 @@ public class ExecutorActorControlService { public Map actorDefinitions = new HashMap<>(); private final int node; + private final NodeConfiguration nodeConfiguration; + private final Logger logger = LoggerFactory.getLogger(getClass()); @Inject public ExecutorActorControlService(MessageQueueFactory messageQueueFactory, + NodeConfigurationService configurationService, BaseServiceParams baseServiceParams, ConvertActor convertActor, ConvertAndLoadActor convertAndLoadActor, @@ -56,12 +62,14 @@ public class ExecutorActorControlService { DownloadSampleActor downloadSampleActor, ScrapeFeedsActor scrapeFeedsActor, ExecutorActorStateMachines stateMachines, - UpdateRssActor updateRssActor) { + UpdateRssActor updateRssActor) throws SQLException { this.messageQueueFactory = messageQueueFactory; this.eventLog = baseServiceParams.eventLog; this.stateMachines = stateMachines; this.node = baseServiceParams.configuration.node(); + this.nodeConfiguration = configurationService.get(node); + register(ExecutorActor.CRAWL, crawlActor); register(ExecutorActor.LIVE_CRAWL, liveCrawlActor); register(ExecutorActor.RECRAWL_SINGLE_DOMAIN, recrawlSingleDomainActor); @@ -95,6 +103,11 @@ public class ExecutorActorControlService { } private void register(ExecutorActor process, RecordActorPrototype graph) { + + if (!process.profileSet.contains(nodeConfiguration.profile())) { + return; + } + var sm = new ActorStateMachine(messageQueueFactory, process.id(), node, UUID.randomUUID(), graph); sm.listen((function, param) -> logStateChange(process, function)); diff --git a/code/execution/java/nu/marginalia/actor/proc/ScrapeFeedsActor.java b/code/execution/java/nu/marginalia/actor/proc/ScrapeFeedsActor.java index 0fbd75e2..d6e2029f 100644 --- a/code/execution/java/nu/marginalia/actor/proc/ScrapeFeedsActor.java +++ b/code/execution/java/nu/marginalia/actor/proc/ScrapeFeedsActor.java @@ -10,6 +10,8 @@ import nu.marginalia.actor.state.ActorResumeBehavior; import nu.marginalia.actor.state.ActorStep; import nu.marginalia.actor.state.Resume; import nu.marginalia.model.EdgeDomain; +import nu.marginalia.nodecfg.NodeConfigurationService; +import nu.marginalia.nodecfg.model.NodeProfile; import nu.marginalia.service.control.ServiceEventLog; import nu.marginalia.service.module.ServiceConfiguration; import org.jsoup.Jsoup; @@ -39,6 +41,7 @@ public class ScrapeFeedsActor extends RecordActorPrototype { private final Duration pollInterval = Duration.ofHours(6); private final ServiceEventLog eventLog; + private final NodeConfigurationService nodeConfigurationService; private final HikariDataSource dataSource; private final int nodeId; @@ -54,8 +57,8 @@ public class ScrapeFeedsActor extends RecordActorPrototype { public ActorStep transition(ActorStep self) throws Exception { return switch(self) { case Initial() -> { - if (nodeId > 1) { - yield new End(); + if (nodeConfigurationService.get(nodeId).profile() != NodeProfile.REALTIME) { + yield new Error("Invalid node profile for RSS update"); } else { yield new Wait(LocalDateTime.now().toString()); @@ -177,10 +180,12 @@ public class ScrapeFeedsActor extends RecordActorPrototype { public ScrapeFeedsActor(Gson gson, ServiceEventLog eventLog, ServiceConfiguration configuration, + NodeConfigurationService nodeConfigurationService, HikariDataSource dataSource) { super(gson); this.eventLog = eventLog; + this.nodeConfigurationService = nodeConfigurationService; this.dataSource = dataSource; this.nodeId = configuration.node(); } diff --git a/code/execution/java/nu/marginalia/actor/proc/UpdateRssActor.java b/code/execution/java/nu/marginalia/actor/proc/UpdateRssActor.java index 3ccad794..344f2920 100644 --- a/code/execution/java/nu/marginalia/actor/proc/UpdateRssActor.java +++ b/code/execution/java/nu/marginalia/actor/proc/UpdateRssActor.java @@ -11,6 +11,8 @@ import nu.marginalia.api.feeds.RpcFeedUpdateMode; import nu.marginalia.mq.MqMessage; import nu.marginalia.mq.MqMessageState; import nu.marginalia.mq.persistence.MqPersistence; +import nu.marginalia.nodecfg.NodeConfigurationService; +import nu.marginalia.nodecfg.model.NodeProfile; import nu.marginalia.service.module.ServiceConfiguration; import java.time.Duration; @@ -25,13 +27,19 @@ public class UpdateRssActor extends RecordActorPrototype { private final Duration updateInterval = Duration.ofHours(24); private final int cleanInterval = 60; + private final NodeConfigurationService nodeConfigurationService; private final MqPersistence persistence; @Inject - public UpdateRssActor(Gson gson, FeedsClient feedsClient, ServiceConfiguration serviceConfiguration, MqPersistence persistence) { + public UpdateRssActor(Gson gson, + FeedsClient feedsClient, + ServiceConfiguration serviceConfiguration, + NodeConfigurationService nodeConfigurationService, + MqPersistence persistence) { super(gson); this.feedsClient = feedsClient; this.nodeId = serviceConfiguration.node(); + this.nodeConfigurationService = nodeConfigurationService; this.persistence = persistence; } @@ -55,9 +63,8 @@ public class UpdateRssActor extends RecordActorPrototype { public ActorStep transition(ActorStep self) throws Exception { return switch (self) { case Initial() -> { - if (nodeId > 1) { - // Only run on the first node - yield new End(); + if (nodeConfigurationService.get(nodeId).profile() != NodeProfile.REALTIME) { + yield new Error("Invalid node profile for RSS update"); } else { // Wait for 5 minutes before starting the first update, to give the system time to start up properly diff --git a/code/execution/java/nu/marginalia/execution/ExecutorGrpcService.java b/code/execution/java/nu/marginalia/execution/ExecutorGrpcService.java index 724edcf7..1b28919f 100644 --- a/code/execution/java/nu/marginalia/execution/ExecutorGrpcService.java +++ b/code/execution/java/nu/marginalia/execution/ExecutorGrpcService.java @@ -15,9 +15,12 @@ import nu.marginalia.service.module.ServiceConfiguration; import nu.marginalia.service.server.DiscoverableService; import nu.marginalia.storage.FileStorageService; import nu.marginalia.storage.model.FileStorageId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Duration; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; @@ -32,6 +35,8 @@ public class ExecutorGrpcService private final ServiceConfiguration serviceConfiguration; private final ExecutorActorControlService actorControlService; + private static final Logger logger = LoggerFactory.getLogger(ExecutorGrpcService.class); + @Inject public ExecutorGrpcService(ActorApi actorApi, FileStorageService fileStorageService, @@ -240,5 +245,22 @@ public class ExecutorGrpcService } } + @Override + public void restartExecutorService(Empty request, StreamObserver responseObserver) { + responseObserver.onNext(Empty.getDefaultInstance()); + responseObserver.onCompleted(); + + logger.info("Restarting executor service on node {}", serviceConfiguration.node()); + + try { + // Wait for the response to be sent before restarting + Thread.sleep(Duration.ofSeconds(5)); + } + catch (InterruptedException e) { + logger.warn("Interrupted while waiting for restart", e); + } + + System.exit(0); + } } diff --git a/code/services-core/control-service/java/nu/marginalia/control/node/svc/ControlNodeService.java b/code/services-core/control-service/java/nu/marginalia/control/node/svc/ControlNodeService.java index 003e950e..62929c83 100644 --- a/code/services-core/control-service/java/nu/marginalia/control/node/svc/ControlNodeService.java +++ b/code/services-core/control-service/java/nu/marginalia/control/node/svc/ControlNodeService.java @@ -12,6 +12,7 @@ import nu.marginalia.control.sys.svc.HeartbeatService; import nu.marginalia.executor.client.ExecutorClient; import nu.marginalia.nodecfg.NodeConfigurationService; import nu.marginalia.nodecfg.model.NodeConfiguration; +import nu.marginalia.nodecfg.model.NodeProfile; import nu.marginalia.service.ServiceId; import nu.marginalia.service.ServiceMonitors; import nu.marginalia.storage.FileStorageService; @@ -52,7 +53,8 @@ public class ControlNodeService { HikariDataSource dataSource, ServiceMonitors monitors, RedirectControl redirectControl, - NodeConfigurationService nodeConfigurationService, ControlCrawlDataService crawlDataService) + NodeConfigurationService nodeConfigurationService, + ControlCrawlDataService crawlDataService) { this.fileStorageService = fileStorageService; this.rendererFactory = rendererFactory; @@ -269,6 +271,8 @@ public class ControlNodeService { String act = request.queryParams("act"); if ("config".equals(act)) { + var oldConfig = nodeConfigurationService.get(nodeId); + var newConfig = new NodeConfiguration( nodeId, request.queryParams("description"), @@ -276,10 +280,19 @@ public class ControlNodeService { "on".equalsIgnoreCase(request.queryParams("autoClean")), "on".equalsIgnoreCase(request.queryParams("includeInPrecession")), "on".equalsIgnoreCase(request.queryParams("keepWarcs")), + NodeProfile.valueOf(request.queryParams("profile")), "on".equalsIgnoreCase(request.queryParams("disabled")) ); nodeConfigurationService.save(newConfig); + + if (!(Objects.equals(oldConfig.profile(), newConfig.profile()))) { + // Restart the executor service if the profile has changed + executorClient.restartExecutorService(nodeId); + } + else if (newConfig.disabled()) { + executorClient.restartExecutorService(nodeId); + } } else if ("storage".equals(act)) { throw new UnsupportedOperationException(); diff --git a/code/services-core/control-service/resources/templates/control/node/node-config.hdb b/code/services-core/control-service/resources/templates/control/node/node-config.hdb index ac15e1bf..e646f113 100644 --- a/code/services-core/control-service/resources/templates/control/node/node-config.hdb +++ b/code/services-core/control-service/resources/templates/control/node/node-config.hdb @@ -21,6 +21,35 @@ + +
+ + + +
The node profile configures which actors are available. +
    +
  • + Batch Crawl - This node is configured for batch crawling. It will not have the sideload actors available. +
  • +
  • + Sideload - This node is configured for sideloading. It will not have the batch crawl actors available. +
  • +
  • + Real Time - This node is configured for real time processing. + It will not have the batch crawl or sideload actors available, but have actors for real time (daily) crawling. +
  • +
  • + Mixed Use - This node is configured for both batch crawling and sideloading. +
  • +
+
+
+
diff --git a/code/services-core/control-service/resources/templates/control/node/partial-node-nav.hdb b/code/services-core/control-service/resources/templates/control/node/partial-node-nav.hdb index 07c7ced3..14c477a3 100644 --- a/code/services-core/control-service/resources/templates/control/node/partial-node-nav.hdb +++ b/code/services-core/control-service/resources/templates/control/node/partial-node-nav.hdb @@ -1,5 +1,5 @@ -

Index Node {{node.id}}

+

Index Node {{node.id}}: {{node.profile}}

{{#if node.disabled}} This index node is disabled! {{/if}} @@ -10,8 +10,10 @@ + {{#unless node.profile.realtime}} + {{/unless}} + {{#unless node.profile.realtime}} + {{/unless}} + + diff --git a/code/services-core/control-service/resources/templates/control/partials/nodes-table.hdb b/code/services-core/control-service/resources/templates/control/partials/nodes-table.hdb index 8a0d4e68..3472a64b 100644 --- a/code/services-core/control-service/resources/templates/control/partials/nodes-table.hdb +++ b/code/services-core/control-service/resources/templates/control/partials/nodes-table.hdb @@ -2,13 +2,16 @@

Nodes

- + {{#each .}} +
NodeQueriesEnabledIndexExecutorNodeProfileQueriesEnabledIndexExecutor
node-{{id}} + {{configuration.profile}} + {{#if configuration.acceptQueries}} ✓