diff options
Diffstat (limited to 'src/main/java/org/traccar/schedule')
8 files changed, 91 insertions, 27 deletions
diff --git a/src/main/java/org/traccar/schedule/ScheduleManager.java b/src/main/java/org/traccar/schedule/ScheduleManager.java index 742428fd8..fd8171148 100644 --- a/src/main/java/org/traccar/schedule/ScheduleManager.java +++ b/src/main/java/org/traccar/schedule/ScheduleManager.java @@ -20,6 +20,9 @@ import org.traccar.LifecycleObject; import jakarta.inject.Inject; import jakarta.inject.Singleton; +import org.traccar.config.Config; +import org.traccar.config.Keys; + import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.stream.Stream; @@ -28,11 +31,13 @@ import java.util.stream.Stream; public class ScheduleManager implements LifecycleObject { private final Injector injector; + private final boolean secondary; private ScheduledExecutorService executor; @Inject - public ScheduleManager(Injector injector) { + public ScheduleManager(Injector injector, Config config) { this.injector = injector; + secondary = config.getBoolean(Keys.BROADCAST_SECONDARY); } @Override @@ -46,7 +51,12 @@ public class ScheduleManager implements LifecycleObject { TaskReports.class, TaskDeviceInactivityCheck.class, TaskWebSocketKeepalive.class) - .forEachOrdered(task -> injector.getInstance(task).schedule(executor)); + .forEachOrdered(taskClass -> { + var task = injector.getInstance(taskClass); + if (task.multipleInstances() || !secondary) { + task.schedule(executor); + } + }); } @Override diff --git a/src/main/java/org/traccar/schedule/ScheduleTask.java b/src/main/java/org/traccar/schedule/ScheduleTask.java index 1b537213b..a2a31ac4f 100644 --- a/src/main/java/org/traccar/schedule/ScheduleTask.java +++ b/src/main/java/org/traccar/schedule/ScheduleTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 2024 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,5 +18,10 @@ package org.traccar.schedule; import java.util.concurrent.ScheduledExecutorService; public interface ScheduleTask extends Runnable { + + default boolean multipleInstances() { + return true; + } + void schedule(ScheduledExecutorService executor); } diff --git a/src/main/java/org/traccar/schedule/SingleScheduleTask.java b/src/main/java/org/traccar/schedule/SingleScheduleTask.java new file mode 100644 index 000000000..a0f1deee4 --- /dev/null +++ b/src/main/java/org/traccar/schedule/SingleScheduleTask.java @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Anton Tananaev (anton@traccar.org) + * + * 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 org.traccar.schedule; + +public abstract class SingleScheduleTask implements ScheduleTask { + @Override + public boolean multipleInstances() { + return false; + } +} diff --git a/src/main/java/org/traccar/schedule/TaskDeleteTemporary.java b/src/main/java/org/traccar/schedule/TaskDeleteTemporary.java index 0cead59fb..eb49b7e46 100644 --- a/src/main/java/org/traccar/schedule/TaskDeleteTemporary.java +++ b/src/main/java/org/traccar/schedule/TaskDeleteTemporary.java @@ -28,7 +28,7 @@ import java.util.Date; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -public class TaskDeleteTemporary implements ScheduleTask { +public class TaskDeleteTemporary extends SingleScheduleTask { private static final Logger LOGGER = LoggerFactory.getLogger(TaskDeleteTemporary.class); diff --git a/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java b/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java index 8e45568d5..9bc98d8d3 100644 --- a/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java +++ b/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java @@ -34,7 +34,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -public class TaskDeviceInactivityCheck implements ScheduleTask { +public class TaskDeviceInactivityCheck extends SingleScheduleTask { private static final Logger LOGGER = LoggerFactory.getLogger(TaskDeviceInactivityCheck.class); diff --git a/src/main/java/org/traccar/schedule/TaskExpirations.java b/src/main/java/org/traccar/schedule/TaskExpirations.java index e16dcd86c..03be0c97f 100644 --- a/src/main/java/org/traccar/schedule/TaskExpirations.java +++ b/src/main/java/org/traccar/schedule/TaskExpirations.java @@ -36,7 +36,7 @@ import org.traccar.storage.query.Request; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -public class TaskExpirations implements ScheduleTask { +public class TaskExpirations extends SingleScheduleTask { private static final Logger LOGGER = LoggerFactory.getLogger(TaskExpirations.class); diff --git a/src/main/java/org/traccar/schedule/TaskHealthCheck.java b/src/main/java/org/traccar/schedule/TaskHealthCheck.java index a60935f18..56ac4b91d 100644 --- a/src/main/java/org/traccar/schedule/TaskHealthCheck.java +++ b/src/main/java/org/traccar/schedule/TaskHealthCheck.java @@ -24,6 +24,8 @@ import org.traccar.config.Keys; import jakarta.inject.Inject; import jakarta.ws.rs.client.Client; +import org.traccar.database.StatisticsManager; + import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -33,6 +35,7 @@ public class TaskHealthCheck implements ScheduleTask { private final Config config; private final Client client; + private final StatisticsManager statisticsManager; private final long gracePeriod = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1); @@ -40,11 +43,16 @@ public class TaskHealthCheck implements ScheduleTask { private boolean enabled; private long period; + private double dropThreshold; + + private int messageLastTotal; + private int messageLastPeriod; @Inject - public TaskHealthCheck(Config config, Client client) { + public TaskHealthCheck(Config config, Client client, StatisticsManager statisticsManager) { this.config = config; this.client = client; + this.statisticsManager = statisticsManager; if (!config.getBoolean(Keys.WEB_DISABLE_HEALTH_CHECK) && System.getProperty("os.name").toLowerCase().startsWith("linux")) { try { @@ -55,6 +63,7 @@ public class TaskHealthCheck implements ScheduleTask { } if (period > 0) { LOGGER.info("Health check enabled with period {}", period); + dropThreshold = config.getDouble(Keys.WEB_HEALTH_CHECK_DROP_THRESHOLD); enabled = true; } } catch (UnsatisfiedLinkError e) { @@ -80,11 +89,28 @@ public class TaskHealthCheck implements ScheduleTask { public void run() { LOGGER.debug("Health check running"); if (System.currentTimeMillis() > gracePeriod) { + boolean success = true; + int status = client.target(getUrl()).request().get().getStatus(); - if (status == 200) { + if (status != 200) { + success = false; + LOGGER.warn("Web health check failed with status {}", status); + } + + int messageCurrentTotal = statisticsManager.messageStoredCount(); + int messageCurrentPeriod = messageCurrentTotal - messageLastTotal; + if (dropThreshold > 0 && messageLastPeriod > 0) { + double drop = messageCurrentPeriod / (double) messageLastPeriod; + if (drop < dropThreshold) { + success = false; + LOGGER.warn("Message health check failed with drop {}", drop); + } + } + messageLastTotal = messageCurrentTotal; + messageLastPeriod = messageCurrentPeriod; + + if (success) { notifyWatchdog(); - } else { - LOGGER.warn("Health check failed with status {}", status); } } else { notifyWatchdog(); diff --git a/src/main/java/org/traccar/schedule/TaskReports.java b/src/main/java/org/traccar/schedule/TaskReports.java index 070fa9d2b..32f6fea87 100644 --- a/src/main/java/org/traccar/schedule/TaskReports.java +++ b/src/main/java/org/traccar/schedule/TaskReports.java @@ -41,6 +41,8 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; import jakarta.inject.Inject; + +import java.time.Instant; import java.util.Collections; import java.util.Date; import java.util.HashSet; @@ -50,7 +52,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -public class TaskReports implements ScheduleTask { +public class TaskReports extends SingleScheduleTask { private static final Logger LOGGER = LoggerFactory.getLogger(TaskReports.class); @@ -83,12 +85,12 @@ public class TaskReports implements ScheduleTask { var lastEvents = calendar.findPeriods(lastCheck); var currentEvents = calendar.findPeriods(currentCheck); - Set<Period> finishedEvents = new HashSet<>(lastEvents); + Set<Period<Instant>> finishedEvents = new HashSet<>(lastEvents); finishedEvents.removeAll(currentEvents); - for (Period period : finishedEvents) { + for (Period<Instant> period : finishedEvents) { RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap()); try (RequestScoper.CloseableScope ignored = scope.open()) { - executeReport(report, period.getStart(), period.getEnd()); + executeReport(report, Date.from(period.getStart()), Date.from(period.getEnd())); } } } @@ -116,34 +118,32 @@ public class TaskReports implements ScheduleTask { for (User user : users) { LogAction.report(user.getId(), true, report.getType(), from, to, deviceIds, groupIds); switch (report.getType()) { - case "events": + case "events" -> { var eventsReportProvider = injector.getInstance(EventsReportProvider.class); reportMailer.sendAsync(user.getId(), stream -> eventsReportProvider.getExcel( stream, user.getId(), deviceIds, groupIds, List.of(), from, to)); - break; - case "route": + } + case "route" -> { var routeReportProvider = injector.getInstance(RouteReportProvider.class); reportMailer.sendAsync(user.getId(), stream -> routeReportProvider.getExcel( stream, user.getId(), deviceIds, groupIds, from, to)); - break; - case "summary": + } + case "summary" -> { var summaryReportProvider = injector.getInstance(SummaryReportProvider.class); reportMailer.sendAsync(user.getId(), stream -> summaryReportProvider.getExcel( stream, user.getId(), deviceIds, groupIds, from, to, false)); - break; - case "trips": + } + case "trips" -> { var tripsReportProvider = injector.getInstance(TripsReportProvider.class); reportMailer.sendAsync(user.getId(), stream -> tripsReportProvider.getExcel( stream, user.getId(), deviceIds, groupIds, from, to)); - break; - case "stops": + } + case "stops" -> { var stopsReportProvider = injector.getInstance(StopsReportProvider.class); reportMailer.sendAsync(user.getId(), stream -> stopsReportProvider.getExcel( stream, user.getId(), deviceIds, groupIds, from, to)); - break; - default: - LOGGER.warn("Unsupported report type {}", report.getType()); - break; + } + default -> LOGGER.warn("Unsupported report type {}", report.getType()); } } } |