From 1a509cb1f43cc4fe59646c7796785faa9a4dd580 Mon Sep 17 00:00:00 2001 From: Daniel Graf Date: Fri, 28 Aug 2026 08:24:20 +0200 Subject: [PATCH 1/4] bugfix(#1212) Return empty TimeRange for null start and end times --- .../reitti/service/processing/LocationPointStagingService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java b/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java index c5d2f1a1..8f3d43c5 100644 --- a/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java +++ b/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java @@ -18,6 +18,7 @@ import java.sql.*; import java.util.List; import java.util.Set; +import java.util.Timer; import java.util.concurrent.ConcurrentHashMap; @Service @@ -145,7 +146,7 @@ public TimeRange getTimeRange(String partitionKey) { Timestamp end = rs.getTimestamp("end_time"); if (start == null || end == null) { - return null; + return TimeRange.empty(); } return new TimeRange(start.toInstant(), end.toInstant()); From ecbfe7e424bc5d09fd5f682ad77336b31abd5685 Mon Sep 17 00:00:00 2001 From: Daniel Graf Date: Fri, 28 Aug 2026 08:24:52 +0200 Subject: [PATCH 2/4] bugfix(#1212) Remove unused Timer import from LocationPointStagingService --- .../reitti/service/processing/LocationPointStagingService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java b/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java index 8f3d43c5..a40bc442 100644 --- a/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java +++ b/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java @@ -18,7 +18,6 @@ import java.sql.*; import java.util.List; import java.util.Set; -import java.util.Timer; import java.util.concurrent.ConcurrentHashMap; @Service From b068fab3d41178545bae7b32a0416be845194fe7 Mon Sep 17 00:00:00 2001 From: Daniel Graf Date: Fri, 28 Aug 2026 08:38:43 +0200 Subject: [PATCH 3/4] bugfix(#1212) Handle missing and empty TimeRange during location data cleanup - Added fallback to recalculate TimeRange if missing - Skipped cleanup task if TimeRange remains empty - Improved logging for better debugging --- .../service/importer/PromotionJobHandler.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/dedicatedcode/reitti/service/importer/PromotionJobHandler.java b/src/main/java/com/dedicatedcode/reitti/service/importer/PromotionJobHandler.java index a6014640..2dd91e27 100644 --- a/src/main/java/com/dedicatedcode/reitti/service/importer/PromotionJobHandler.java +++ b/src/main/java/com/dedicatedcode/reitti/service/importer/PromotionJobHandler.java @@ -78,14 +78,22 @@ public void execute(JobExecutionContext context) throws JobExecutionException { metadataRepository.updateProgress(jobId, 2, 3, "Scheduling cleanup job"); if (promote > 0) { - this.userNotificationService.newLocationData(user, data.device, timeRange); - this.jobSchedulingService.enqueueTask(locationDataCleanupTask, - new LocationDataCleanupTask.TaskData(user, data.getDevice(), timeRange.start(), timeRange.end()).withParentJobId(data.getParentJobId()), - JobSchedulingService.Metadata.builder() - .user(user) - .jobType(JobType.LOCATION_DATA_CLEANUP) - .friendlyName("Location Data Cleanup") - .build()); + if (timeRange.equals(TimeRange.empty())) { + log.debug("No timerange found for partitionKey [{}], recalculating", partitionKey); + timeRange = this.stagingService.getWholeTimeRange(partitionKey); + } + if (timeRange.equals(TimeRange.empty())) { + log.warn("Still no timerange found for partitionKey [{}], skipping cleanup", partitionKey); + } else { + this.userNotificationService.newLocationData(user, data.device, timeRange); + this.jobSchedulingService.enqueueTask(locationDataCleanupTask, + new LocationDataCleanupTask.TaskData(user, data.getDevice(), timeRange.start(), timeRange.end()).withParentJobId(data.getParentJobId()), + JobSchedulingService.Metadata.builder() + .user(user) + .jobType(JobType.LOCATION_DATA_CLEANUP) + .friendlyName("Location Data Cleanup") + .build()); + } } else { log.debug("No points to promote, timerange was [{}]", timeRange); } From ed60530fba2750568437cf23d33767189775b973 Mon Sep 17 00:00:00 2001 From: Daniel Graf Date: Fri, 28 Aug 2026 08:38:52 +0200 Subject: [PATCH 4/4] bugfix(#1212) Add method to calculate full TimeRange for staging location points - Implemented `getWholeTimeRange` to retrieve the full time range from staging points. - Returns empty `TimeRange` for null `start_time` and `end_time`. --- .../processing/LocationPointStagingService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java b/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java index a40bc442..3e4da308 100644 --- a/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java +++ b/src/main/java/com/dedicatedcode/reitti/service/processing/LocationPointStagingService.java @@ -138,6 +138,20 @@ ON CONFLICT (user_id, device_id, timestamp) DO NOTHING return insertedIds.size(); } + public TimeRange getWholeTimeRange(String partitionKey) { + String sql = "SELECT MIN(timestamp) as start_time, MAX(timestamp) as end_time FROM staging_location_points WHERE partition_key = ?"; + return this.jdbcTemplate.queryForObject(sql, (rs, rowNum) -> { + Timestamp start = rs.getTimestamp("start_time"); + Timestamp end = rs.getTimestamp("end_time"); + + if (start == null || end == null) { + return TimeRange.empty(); + } + + return new TimeRange(start.toInstant(), end.toInstant()); + }, partitionKey); + } + public TimeRange getTimeRange(String partitionKey) { String sql = "SELECT MIN(timestamp) as start_time, MAX(timestamp) as end_time FROM staging_location_points WHERE partition_key = ? AND promoted = FALSE"; return this.jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {