diff --git a/node/impl/src/main/java/eu/cloudnetservice/node/impl/Node.java b/node/impl/src/main/java/eu/cloudnetservice/node/impl/Node.java index 5759f58968..a942727bb9 100644 --- a/node/impl/src/main/java/eu/cloudnetservice/node/impl/Node.java +++ b/node/impl/src/main/java/eu/cloudnetservice/node/impl/Node.java @@ -55,6 +55,7 @@ import eu.cloudnetservice.node.impl.module.updater.ModuleUpdaterRegistry; import eu.cloudnetservice.node.impl.network.chunk.FileDeployCallbackListener; import eu.cloudnetservice.node.impl.network.chunk.FileQueryChannelMessageListener; +import eu.cloudnetservice.node.impl.service.defaults.log.ServiceWatchdogListener; import eu.cloudnetservice.node.impl.setup.DefaultInstallation; import eu.cloudnetservice.node.impl.template.LocalTemplateStorage; import eu.cloudnetservice.node.impl.tick.DefaultShutdownHandler; @@ -484,6 +485,7 @@ private void finishStartup( eventManager.registerListener(callbackListener); eventManager.callEvent(new CloudNetNodePostInitializationEvent()); eventManager.registerListener(FileQueryChannelMessageListener.class); + eventManager.registerListener(ServiceWatchdogListener.class); // notify that we are done & start the main tick loop LOGGER.info(i18n.translate("start-done", Duration.between(startInstant, Instant.now()).toMillis())); diff --git a/node/impl/src/main/java/eu/cloudnetservice/node/impl/service/defaults/DefaultCloudServiceManager.java b/node/impl/src/main/java/eu/cloudnetservice/node/impl/service/defaults/DefaultCloudServiceManager.java index 465e4f658e..af6b0ad956 100644 --- a/node/impl/src/main/java/eu/cloudnetservice/node/impl/service/defaults/DefaultCloudServiceManager.java +++ b/node/impl/src/main/java/eu/cloudnetservice/node/impl/service/defaults/DefaultCloudServiceManager.java @@ -53,11 +53,11 @@ import eu.cloudnetservice.node.impl.service.defaults.factory.JVMLocalCloudServiceFactory; import eu.cloudnetservice.node.impl.service.defaults.provider.EmptySpecificCloudServiceProvider; import eu.cloudnetservice.node.impl.service.defaults.provider.RemoteNodeCloudServiceProvider; -import eu.cloudnetservice.node.impl.tick.DefaultTickLoop; import eu.cloudnetservice.node.service.CloudService; import eu.cloudnetservice.node.service.CloudServiceManager; import eu.cloudnetservice.node.service.LocalCloudServiceFactory; import eu.cloudnetservice.node.service.ServiceConfigurationPreparer; +import eu.cloudnetservice.node.tick.Scheduler; import eu.cloudnetservice.utils.base.concurrent.TaskUtil; import io.vavr.Tuple2; import jakarta.inject.Inject; @@ -88,6 +88,9 @@ @Provides({InternalCloudServiceManager.class, CloudServiceManager.class, CloudServiceProvider.class}) public class DefaultCloudServiceManager implements InternalCloudServiceManager { + protected static final int SERVICE_WATCHDOG_INTERVAL_MILLIS = + Integer.getInteger("cloudnet.service-watchdog-interval-millis", 1000); + protected static final Path TEMP_SERVICE_DIR = Path.of( System.getProperty("cloudnet.tempDir.services", "temp/services")); protected static final Path PERSISTENT_SERVICE_DIR = Path.of( @@ -117,7 +120,6 @@ public class DefaultCloudServiceManager implements InternalCloudServiceManager { @Inject public DefaultCloudServiceManager( - @NonNull DefaultTickLoop mainThread, @NonNull RPCFactory rpcFactory, @NonNull EventManager eventManager, @NonNull DataSyncRegistry dataSyncRegistry, @@ -170,9 +172,16 @@ public DefaultCloudServiceManager( }) .currentGetter(group -> this.serviceProviderByName(group.name()).serviceInfo()) .build()); + } + + @Inject + private void registerDefaultServiceFactory() { + this.addCloudServiceFactory("jvm", JVMLocalCloudServiceFactory.class); + } - // schedule the service watchdog to run once per second - mainThread.scheduleTask(() -> { + @Inject + private void scheduleWatchdog(@NonNull Scheduler scheduler, @NonNull EventManager eventManager) { + scheduler.scheduleTask(() -> { for (var service : this.localCloudServices()) { if (service.lifeCycle() == ServiceLifeCycle.RUNNING && !service.alive()) { eventManager.callEvent(new CloudServicePreForceStopEvent(service)); @@ -181,12 +190,7 @@ public DefaultCloudServiceManager( } } return null; - }, Duration.ofMillis(DefaultTickLoop.MILLIS_BETWEEN_TICKS)); - } - - @Inject - private void registerDefaultServiceFactory() { - this.addCloudServiceFactory("jvm", JVMLocalCloudServiceFactory.class); + }, Duration.ofMillis(SERVICE_WATCHDOG_INTERVAL_MILLIS)); } @Override diff --git a/node/impl/src/main/java/eu/cloudnetservice/node/impl/service/defaults/log/ServiceWatchdogListener.java b/node/impl/src/main/java/eu/cloudnetservice/node/impl/service/defaults/log/ServiceWatchdogListener.java new file mode 100644 index 0000000000..3085a46513 --- /dev/null +++ b/node/impl/src/main/java/eu/cloudnetservice/node/impl/service/defaults/log/ServiceWatchdogListener.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-present CloudNetService team & contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.cloudnetservice.node.impl.service.defaults.log; + +import eu.cloudnetservice.driver.event.EventListener; +import eu.cloudnetservice.node.event.service.CloudServicePreForceStopEvent; +import jakarta.inject.Singleton; +import java.util.concurrent.TimeUnit; +import lombok.NonNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Singleton +public final class ServiceWatchdogListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceWatchdogListener.class); + private static final long SERVICE_LOG_THRESHOLD_MILLIS = + TimeUnit.SECONDS.toMillis(Integer.getInteger("cloudnet.service-watchdog-threshold-seconds", 5)); + + @EventListener + private void handleCloudServicePreForceStop(@NonNull CloudServicePreForceStopEvent event) { + var connectionTime = event.serviceInfo().connectedTime(); + if (SERVICE_LOG_THRESHOLD_MILLIS <= 0) { + return; + } + + if (connectionTime == -1 || System.currentTimeMillis() - connectionTime < SERVICE_LOG_THRESHOLD_MILLIS) { + for (var cachedLogMessage : event.service().cachedLogMessages()) { + LOGGER.debug("[{}/WATCHDOG] {}", event.serviceInfo().name(), cachedLogMessage); + } + } + } +}