Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Run full update for cont analytics table job if first time [DHIS2-16986] #18505

Merged
merged 1 commit into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/DateUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,16 @@ public static String toLongDateWithMillis(Date date) {
return date != null ? LONG_DATE_FORMAT_WITH_MILLIS.print(new DateTime(date)) : null;
}

/**
* Formats a Date to the format yyyy-MM-dd HH:mm:ss.
*
* @param date the Date to parse.
* @return A formatted date string.
*/
public static String toLongDate(Date date) {
return date != null ? LONG_DATE_FORMAT.print(new DateTime(date)) : null;
}

/**
* Formats a Date to the format yyyy-MM-dd HH:mm:ss.
*
Expand Down Expand Up @@ -258,6 +268,20 @@ public static Date minusOneDay(Date date) {
return new Date(date.getTime() - MS_PER_DAY);
}

/**
* Creates a {@link Date} representing the given year, month and day.
*
* @param year the year.
* @param month the month, from 1.
* @param dayOfMonth the day of the month, from 1.
* @param hourOfDay the hour of day, from 0.
* @param minuteOfHour the minute of hour, from 0.
* @return a {@link Date}.
*/
public static Date getDate(int year, int month, int dayOfMonth, int hourOfDay, int minuteOfHour) {
return new DateTime(year, month, dayOfMonth, hourOfDay, minuteOfHour).toDate();
}

/**
* Formats a Date according to the HTTP specification standard date format.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@
*/
package org.hisp.dhis.analytics.table.scheduling;

import static com.google.common.base.MoreObjects.firstNonNull;
import static org.hisp.dhis.util.DateUtils.getLongDateString;
import static org.hisp.dhis.util.DateUtils.toLongDate;

import com.google.common.base.Preconditions;
import java.util.Date;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.hisp.dhis.analytics.AnalyticsTableGenerator;
import org.hisp.dhis.analytics.AnalyticsTableUpdateParams;
import org.hisp.dhis.scheduling.Job;
Expand Down Expand Up @@ -79,24 +80,14 @@ public void execute(JobConfiguration jobConfiguration, JobProgress progress) {
ContinuousAnalyticsJobParameters parameters =
(ContinuousAnalyticsJobParameters) jobConfiguration.getJobParameters();

Integer fullUpdateHourOfDay =
ObjectUtils.firstNonNull(parameters.getFullUpdateHourOfDay(), DEFAULT_HOUR_OF_DAY);

Date now = new Date();
Date defaultNextFullUpdate = DateUtils.getNextDate(fullUpdateHourOfDay, now);
Date nextFullUpdate =
systemSettingManager.getSystemSetting(
SettingKey.NEXT_ANALYTICS_TABLE_UPDATE, defaultNextFullUpdate);
final int fullUpdateHourOfDay =
firstNonNull(parameters.getFullUpdateHourOfDay(), DEFAULT_HOUR_OF_DAY);
final Date startTime = new Date();

log.info(
"Starting continuous analytics table update, current time: '{}', default next full update: '{}', next full update: '{}'",
getLongDateString(now),
getLongDateString(defaultNextFullUpdate),
getLongDateString(nextFullUpdate));
"Starting continuous analytics table update, current time: '{}'", toLongDate(startTime));

Preconditions.checkNotNull(nextFullUpdate);

if (now.after(nextFullUpdate)) {
if (runFullUpdate(startTime)) {
log.info("Performing full analytics table update");

AnalyticsTableUpdateParams params =
Expand All @@ -105,13 +96,13 @@ public void execute(JobConfiguration jobConfiguration, JobProgress progress) {
.withSkipResourceTables(false)
.withSkipTableTypes(parameters.getSkipTableTypes())
.withJobId(jobConfiguration)
.withStartTime(now)
.withStartTime(startTime)
.build();

try {
analyticsTableGenerator.generateTables(params, progress);
} finally {
Date nextUpdate = DateUtils.getNextDate(fullUpdateHourOfDay, now);
Date nextUpdate = DateUtils.getNextDate(fullUpdateHourOfDay, startTime);
systemSettingManager.saveSystemSetting(SettingKey.NEXT_ANALYTICS_TABLE_UPDATE, nextUpdate);
log.info("Next full analytics table update: '{}'", getLongDateString(nextUpdate));
}
Expand All @@ -124,10 +115,28 @@ public void execute(JobConfiguration jobConfiguration, JobProgress progress) {
.withSkipResourceTables(true)
.withSkipTableTypes(parameters.getSkipTableTypes())
.withJobId(jobConfiguration)
.withStartTime(now)
.withStartTime(startTime)
.build();

analyticsTableGenerator.generateTables(params, progress);
}
}

/**
* Indicates whether a full table update should be run. If the next full update time is not set,
* it indicates that a full update has never been run for this job, and a full update should be
* run immediately. Otherwise, a full update is run if the job start time argument is after the
* next full update time.
*
* @param startTime the job start time.
* @return true if a full table update should be run.
*/
boolean runFullUpdate(Date startTime) {
Objects.requireNonNull(startTime);

Date nextFullUpdate =
systemSettingManager.getSystemSetting(SettingKey.NEXT_ANALYTICS_TABLE_UPDATE, Date.class);

return nextFullUpdate == null || startTime.after(nextFullUpdate);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2004-2024, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* Neither the name of the HISP project nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hisp.dhis.analytics.table.scheduling;

import static org.hisp.dhis.setting.SettingKey.NEXT_ANALYTICS_TABLE_UPDATE;
import static org.hisp.dhis.util.DateUtils.getDate;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.when;

import java.util.Date;
import org.hisp.dhis.analytics.AnalyticsTableGenerator;
import org.hisp.dhis.setting.SystemSettingManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class ContinuousAnalyticsTableJobTest {
@Mock private AnalyticsTableGenerator analyticsTableGenerator;

@Mock private SystemSettingManager systemSettingManager;

private ContinuousAnalyticsTableJob job;

private final Date dateA = getDate(2024, 1, 4, 23, 0);
private final Date dateB = getDate(2024, 1, 5, 2, 0);
private final Date dateC = getDate(2024, 1, 5, 8, 0);

@BeforeEach
public void beforeEach() {
job = new ContinuousAnalyticsTableJob(analyticsTableGenerator, systemSettingManager);
}

@Test
void testRunFullUpdate() {
when(systemSettingManager.getSystemSetting(NEXT_ANALYTICS_TABLE_UPDATE, Date.class))
.thenReturn(dateB);

assertFalse(job.runFullUpdate(dateA));
assertTrue(job.runFullUpdate(dateC));
}

@Test
void testRunFullUpdateNullNextUpdate() {
when(systemSettingManager.getSystemSetting(NEXT_ANALYTICS_TABLE_UPDATE, Date.class))
.thenReturn(null);

assertTrue(job.runFullUpdate(dateA));
assertTrue(job.runFullUpdate(dateC));
}
}
Loading