diff --git a/.github/workflows/deploy.to.dev.jinil.yml b/.github/workflows/deploy.to.dev.jinil.yml
deleted file mode 100644
index 814b1fe8..00000000
--- a/.github/workflows/deploy.to.dev.jinil.yml
+++ /dev/null
@@ -1,129 +0,0 @@
-name: Build & Deploy to DEV-Jinil
-
-env:
- # 🖊️ EDIT your repository secrets to log into your OpenShift cluster and set up the context.
- # See https://github.com/redhat-actions/oc-login#readme for how to retrieve these values.
- # To get a permanent token, refer to https://github.com/redhat-actions/oc-login/wiki/Using-a-Service-Account-for-GitHub-Actions
- OPENSHIFT_SERVER: ${{ secrets.OPENSHIFT_SERVER }}
- OPENSHIFT_TOKEN: ${{ secrets.OPENSHIFT_TOKEN }}
- OPENSHIFT_NAMESPACE: ${{ secrets.GRAD_NAMESPACE }}-dev
- COMMON_NAMESPACE: ${{ secrets.COMMON_NAMESPACE }}
- NAMESPACE: ${{ secrets.GRAD_NAMESPACE }}
- BUSINESS_NAMESPACE: ${{ secrets.GRAD_BUSINESS_NAMESPACE }}
-
- # 🖊️ EDIT to change the image registry settings.
- # Registries such as GHCR, Quay.io, and Docker Hub are supported.
- IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
- IMAGE_REGISTRY_USER: ${{ github.actor }}
- IMAGE_REGISTRY_PASSWORD: ${{ github.token }}
-
- SPRING_BOOT_IMAGE_NAME: educ-grad-batch-graduation-api-dc
- DOCKER_ARTIFACTORY_REPO: artifacts.developer.gov.bc.ca/docker-remote
-
- REPO_NAME: "educ-grad-batch-graduation-api"
- APP_DOMAIN: ${{ secrets.APP_DOMAIN }}
- BRANCH: "main"
- TAG: "latest"
- MIN_CPU: "50m"
- MAX_CPU: "300m"
- MIN_MEM: "1024Mi"
- MAX_MEM: "4Gi"
- MIN_REPLICAS: "3"
- MAX_REPLICAS: "3"
-
-on:
- # https://docs.github.com/en/actions/reference/events-that-trigger-workflows
- workflow_dispatch:
-
-jobs:
- openshift-ci-cd:
- name: Build and deploy to OpenShift DEV
- # ubuntu-20.04 can also be used.
- runs-on: ubuntu-20.04
- environment: dev
-
- #outputs:
- #ROUTE: ${{ steps.deploy-and-expose.outputs.route }}
- #SELECTOR: ${{ steps.deploy-and-expose.outputs.selector }}
-
- steps:
- - name: Check out repository
- uses: actions/checkout@v3
- with:
- ref: develop/jinil
-
- - name: Determine image tags
- if: env.TAG == ''
- run: |
- echo "TAG=latest ${GITHUB_SHA::12}" | tee -a $GITHUB_ENV
-
- - name: Login to Docker Hub
- uses: docker/login-action@v2
- with:
- registry: ${{ env.DOCKER_ARTIFACTORY_REPO }}
- username: ${{ secrets.DOCKER_ARTIFACTORY_USERNAME }}
- password: ${{ secrets.DOCKER_ARTIFACTORY_ACCESS_TOKEN }}
-
- # https://github.com/redhat-actions/buildah-build#readme
- - name: Build from Dockerfile
- id: build-image
- uses: redhat-actions/buildah-build@v2
- with:
- image: ${{ env.REPO_NAME }}
- tags: ${{ env.TAG }}
-
- # If you don't have a Dockerfile/Containerfile, refer to https://github.com/redhat-actions/buildah-build#scratch-build-inputs
- # Or, perform a source-to-image build using https://github.com/redhat-actions/s2i-build
- # Otherwise, point this to your Dockerfile/Containerfile relative to the repository root.
- dockerfiles: |
- ./Dockerfile
-
- # https://github.com/redhat-actions/push-to-registry#readme
- - name: Push to registry
- id: push-image
- uses: redhat-actions/push-to-registry@v2
- with:
- image: ${{ steps.build-image.outputs.image }}
- tags: ${{ steps.build-image.outputs.tags }}
- registry: ${{ env.IMAGE_REGISTRY }}
- username: ${{ env.IMAGE_REGISTRY_USER }}
- password: ${{ env.IMAGE_REGISTRY_PASSWORD }}
-
- # The path the image was pushed to is now stored in ${{ steps.push-image.outputs.registry-path }}
- - name: Install oc
- uses: redhat-actions/openshift-tools-installer@v1
- with:
- oc: 4
-
- # https://github.com/redhat-actions/oc-login#readme
- - name: Deploy
- run: |
- set -eux
- # Login to OpenShift and select project
- oc login --token=${{ env.OPENSHIFT_TOKEN }} --server=${{ env.OPENSHIFT_SERVER }}
- oc project ${{ env.OPENSHIFT_NAMESPACE }}
- # Cancel any rollouts in progress
- oc rollout cancel dc/${{ env.SPRING_BOOT_IMAGE_NAME }} 2> /dev/null \
- || true && echo "No rollout in progress"
- # tag image stream
- oc -n ${{ env.OPENSHIFT_NAMESPACE }} tag ${{ steps.push-image.outputs.registry-path }} ${{ env.REPO_NAME }}:${{ env.TAG }}
-
- # Process and apply deployment template
- oc process -f tools/openshift/api.dc.yaml -p IS_NAMESPACE=${{ env.OPENSHIFT_NAMESPACE }} -p REPO_NAME=${{ env.REPO_NAME }} -p TAG_NAME=${{ env.TAG }} -p HOST_ROUTE=${{ env.REPO_NAME }}-${{ env.OPENSHIFT_NAMESPACE }}.${{ env.APP_DOMAIN }} -p MIN_REPLICAS=${{ env.MIN_REPLICAS }} -p MAX_REPLICAS=${{ env.MAX_REPLICAS }} -p MIN_CPU=${{ env.MIN_CPU }} -p MAX_CPU=${{ env.MAX_CPU }} -p MIN_MEM=${{ env.MIN_MEM }} -p MAX_MEM=${{ env.MAX_MEM }} \
- | oc apply -f -
-
- # UPDATE Configmaps
- curl -s https://raw.githubusercontent.com/bcgov/${{ env.REPO_NAME }}/${{ env.BRANCH }}/tools/update-configmap.sh | bash /dev/stdin dev ${{ env.REPO_NAME }} ${{ env.NAMESPACE }} ${{ env.COMMON_NAMESPACE }} ${{ secrets.SPLUNK_TOKEN }}
-
- # Start rollout (if necessary) and follow it
- oc rollout latest dc/${{ env.SPRING_BOOT_IMAGE_NAME }} 2> /dev/null \
- || true && echo "Rollout in progress"
- oc logs -f dc/${{ env.SPRING_BOOT_IMAGE_NAME }}
- # Get status, returns 0 if rollout is successful
- oc rollout status dc/${{ env.SPRING_BOOT_IMAGE_NAME }}
-
- # now hit it with a zap scan
- - name: ZAP Scan
- uses: zaproxy/action-api-scan@v0.1.0
- with:
- target: 'https://${{ env.REPO_NAME }}-${{ env.OPENSHIFT_NAMESPACE }}-dev.apps.silver.devops.gov.bc.ca/api/v1/api-docs'
diff --git a/Dockerfile b/Dockerfile
index 745092a2..861508e1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -14,7 +14,7 @@ ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
-ENTRYPOINT ["java","-Duser.name=EDUC_GRAD_BATCH_GRADUATION_API","-Xms4000m","-Xmx4000m","-noverify","-XX:TieredStopAtLevel=1",\
+ENTRYPOINT ["java","-Duser.name=EDUC_GRAD_BATCH_GRADUATION_API","-Xms3000m","-Xmx3800m","-noverify","-XX:TieredStopAtLevel=1",\
"-XX:+UseParallelGC","-XX:MinHeapFreeRatio=20","-XX:MaxHeapFreeRatio=40","-XX:GCTimeRatio=4",\
"-XX:AdaptiveSizePolicyWeight=90","-XX:MaxMetaspaceSize=500m","-XX:ParallelGCThreads=1",\
"-Djava.util.concurrent.ForkJoinPool.common.parallelism=1","-XX:CICompilerCount=2",\
diff --git a/api/pom.xml b/api/pom.xml
index d5cf5ee4..95d49225 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -6,7 +6,7 @@
ca.bc.gov.educ
educ-grad-batch-graduation-api
- 1.8.50
+ 1.8.53
educ-grad-batch-graduation-api
Ministry of Education GRAD BATCH GRADUATION API
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/AsyncConfig.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/AsyncConfig.java
index 084cce6a..4c66469d 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/AsyncConfig.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/AsyncConfig.java
@@ -1,24 +1,18 @@
package ca.bc.gov.educ.api.batchgraduation.config;
-import ca.bc.gov.educ.api.batchgraduation.util.EducGradBatchGraduationApiConstants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
@Profile("!test")
public class AsyncConfig {
@Bean(name = "asyncExecutor")
- public TaskExecutor asyncExecutor(EducGradBatchGraduationApiConstants constants) {
- ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
- executor.setCorePoolSize(constants.getNumberOfPartitions());
- executor.setMaxPoolSize(constants.getNumberOfPartitions());
- executor.setThreadNamePrefix("async-");
- executor.initialize();
- return executor;
+ public TaskExecutor asyncExecutor() {
+ return new SimpleAsyncTaskExecutor("async-");
}
}
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchConfig.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchConfig.java
index c3c53202..51afdca1 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchConfig.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchConfig.java
@@ -29,7 +29,7 @@ public class BatchConfig {
public JobLauncher asyncJobLauncher(JobRepository jobRepository) throws Exception {
TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher();
jobLauncher.setJobRepository(jobRepository);
- jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor());
+ jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor("asyncTask-"));
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchJobConfig.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchJobConfig.java
index 0946217c..2c5cce72 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchJobConfig.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchJobConfig.java
@@ -23,8 +23,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionException;
@@ -33,7 +33,7 @@
import java.util.UUID;
@Configuration
-@EnableBatchProcessing
+@EnableBatchProcessing(isolationLevelForCreate = "ISOLATION_READ_COMMITTED")
public class BatchJobConfig {
// Partitioning for Regular Grad Run updates
@@ -87,7 +87,7 @@ public Step masterStepRegGrad(JobRepository jobRepository, EducGradBatchGraduati
.partitioner(graduationJobStep(jobRepository, skipListener).getName(), partitionerRegGrad())
.step(graduationJobStep(jobRepository, skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -97,7 +97,7 @@ public Step masterStepRegGradError(JobRepository jobRepository, EducGradBatchGra
.partitioner(graduationJobErrorStep(jobRepository, skipListener).getName(), partitionerRegGradRetry())
.step(graduationJobErrorStep(jobRepository, skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -107,7 +107,7 @@ public Step masterStepRegGradErrorRetry(JobRepository jobRepository, EducGradBat
.partitioner(graduationJobErrorRetryStep(jobRepository, skipListener).getName(), partitionerRegGradRetry())
.step(graduationJobErrorRetryStep(jobRepository, skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -230,7 +230,7 @@ public Step masterStepTvrRun(JobRepository jobRepository, EducGradBatchGraduatio
.partitioner(tvrJobStep(jobRepository,skipListener).getName(), partitionerTvrRun())
.step(tvrJobStep(jobRepository,skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -240,7 +240,7 @@ public Step masterStepTvrRunError(JobRepository jobRepository, EducGradBatchGrad
.partitioner(tvrJobErrorStep(jobRepository,skipListener).getName(), partitionerTvrRunRetry())
.step(tvrJobErrorStep(jobRepository,skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -250,7 +250,7 @@ public Step masterStepTvrRunErrorRetry(JobRepository jobRepository, EducGradBatc
.partitioner(tvrJobErrorRetryStep(jobRepository,skipListener).getName(), partitionerTvrRunRetry())
.step(tvrJobErrorRetryStep(jobRepository,skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -362,7 +362,7 @@ public Step masterStepSpcRegGrad(JobRepository jobRepository, EducGradBatchGradu
.partitioner(slaveSpcRegGradStep(jobRepository,skipListener).getName(), partitionerSpcRegGrad())
.step(slaveSpcRegGradStep(jobRepository,skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -372,7 +372,7 @@ public Step masterStepSpcRegGradError(JobRepository jobRepository, EducGradBatch
.partitioner(slaveSpcRegGradErrorStep(jobRepository,skipListener).getName(), partitionerSpcRegGradRetry())
.step(slaveSpcRegGradErrorStep(jobRepository,skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -382,7 +382,7 @@ public Step masterStepSpcRegGradErrorRetry(JobRepository jobRepository, EducGrad
.partitioner(slaveSpcRegGradErrorRetryStep(jobRepository,skipListener).getName(), partitionerSpcRegGradRetry())
.step(slaveSpcRegGradErrorRetryStep(jobRepository,skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -491,7 +491,7 @@ public Step masterStepSpcTvrRun(JobRepository jobRepository, EducGradBatchGradua
.partitioner(slaveStepSpcTvrRun(jobRepository,skipListener).getName(), partitionerSpcRegGrad())
.step(slaveStepSpcTvrRun(jobRepository,skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -501,7 +501,7 @@ public Step masterStepSpcTvrRunError(JobRepository jobRepository, EducGradBatchG
.partitioner(slaveStepSpcTvrRunError(jobRepository,skipListener).getName(), partitionerSpcRegGradRetry())
.step(slaveStepSpcTvrRunError(jobRepository,skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -511,7 +511,7 @@ public Step masterStepSpcTvrRunErrorRetry(JobRepository jobRepository, EducGradB
.partitioner(slaveStepSpcTvrRunErrorRetry(jobRepository,skipListener).getName(), partitionerSpcRegGradRetry())
.step(slaveStepSpcTvrRunErrorRetry(jobRepository,skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -669,7 +669,7 @@ public Step masterStepDisRun(JobRepository jobRepository, EducGradBatchGraduatio
.partitioner(slaveStepDisRun(jobRepository).getName(), partitionerDisRun())
.step(slaveStepDisRun(jobRepository))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -701,7 +701,7 @@ public Step masterStepDisRunYearly(JobRepository jobRepository, EducGradBatchGra
.partitioner(slaveStepDisRun(jobRepository).getName(), partitionerDisRunYearly())
.step(slaveStepDisRunYearly(jobRepository))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -727,7 +727,7 @@ public Step masterStepDisRunYearlyNonGrad(JobRepository jobRepository, EducGradB
.partitioner(slaveStepDisRunYearlyNonGradByMincode(jobRepository).getName(), partitionerDisRunYearlyNonGrad())
.step(slaveStepDisRunYearlyNonGradByMincode(jobRepository))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -753,7 +753,7 @@ public Step masterStepDisRunSupplemental(JobRepository jobRepository, EducGradBa
.partitioner(slaveStepDisRun(jobRepository).getName(), partitionerDisRunSupplemental())
.step(slaveStepDisRun(jobRepository))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -785,7 +785,7 @@ public Step masterStepUserReqDisRun(JobRepository jobRepository, EducGradBatchGr
.partitioner(slaveStepDisRun(jobRepository).getName(), partitionerDisRunUserReq())
.step(slaveStepDisRun(jobRepository))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -847,7 +847,7 @@ public Step masterStepBlankUserReqDisRun(JobRepository jobRepository, EducGradBa
.partitioner(slaveStepBlankDisRun(jobRepository).getName(), partitionerDisRunBlankUserReq())
.step(slaveStepBlankDisRun(jobRepository))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -910,7 +910,7 @@ public Step masterStepPsiUserReqDisRun(JobRepository jobRepository, EducGradBatc
.partitioner(slaveStepPsiDisRun(jobRepository).getName(), partitionerDisRunPsiUserReq())
.step(slaveStepPsiDisRun(jobRepository))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -958,7 +958,7 @@ public Step masterStepCertRegen(JobRepository jobRepository, EducGradBatchGradua
.partitioner(certRegenJobStep(jobRepository, skipListener).getName(), partitionerCertRegen())
.step(certRegenJobStep(jobRepository, skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -1022,7 +1022,7 @@ public Step masterStepEdwSnapshotSchool(JobRepository jobRepository, EducGradBat
.partitioner(edwSnapshotSchoolJobStep(jobRepository, skipListener).getName(), partitionerEDWSnapshotSchool())
.step(edwSnapshotSchoolJobStep(jobRepository, skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -1072,7 +1072,7 @@ public Step masterStepEdwSnapshot(JobRepository jobRepository, EducGradBatchGrad
.partitioner(edwSnapshotJobStep(jobRepository, skipListener).getName(), partitionerEDWSnapshot())
.step(edwSnapshotJobStep(jobRepository, skipListener))
.gridSize(constants.getNumberOfPartitions())
- .taskExecutor(taskExecutor(constants))
+ .taskExecutor(taskExecutor())
.build();
}
@@ -1155,12 +1155,7 @@ public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() {
}
@Bean
- public TaskExecutor taskExecutor(EducGradBatchGraduationApiConstants constants) {
- ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
- executor.setCorePoolSize(constants.getNumberOfPartitions());
- executor.setMaxPoolSize(constants.getNumberOfPartitions());
- executor.setThreadNamePrefix("partition-");
- executor.initialize();
- return executor;
+ public TaskExecutor taskExecutor() {
+ return new SimpleAsyncTaskExecutor("partition-");
}
}
\ No newline at end of file
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchJobLauncher.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchJobLauncher.java
index db5ad3fc..c2789099 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchJobLauncher.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/BatchJobLauncher.java
@@ -2,6 +2,7 @@
import ca.bc.gov.educ.api.batchgraduation.entity.BatchProcessingEntity;
import ca.bc.gov.educ.api.batchgraduation.service.GradDashboardService;
+import net.javacrumbs.shedlock.core.LockAssert;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,6 +47,7 @@ public class BatchJobLauncher {
private Job userScheduledBatchJobRefresher;
@Autowired
+ @Qualifier("asyncJobLauncher")
private JobLauncher jobLauncher;
@Autowired
@@ -66,9 +68,10 @@ public class BatchJobLauncher {
private static final String ERROR_MSG = "Error {}";
@Scheduled(cron = "${batch.regalg.cron}")
- @SchedulerLock(name = "GraduationBatchJob", lockAtLeastFor = "20s", lockAtMostFor = "1200m")
+ @SchedulerLock(name = "GraduationBatchJob", lockAtLeastFor = "${batch.system.scheduled.routines.lockAtLeastFor}", lockAtMostFor = "${batch.system.scheduled.routines.lockAtMostFor}")
public void runRegularGradAlgorithm() {
LOGGER.info(BATCH_STARTED);
+ LockAssert.assertLocked();
JobParametersBuilder builder = new JobParametersBuilder();
builder.addLong(TIME, System.currentTimeMillis()).toJobParameters();
builder.addString(JOB_TRIGGER, BATCH_TRIGGER);
@@ -86,9 +89,10 @@ public void runRegularGradAlgorithm() {
}
@Scheduled(cron = "${batch.tvrrun.cron}")
- @SchedulerLock(name = "tvrBatchJob", lockAtLeastFor = "20s", lockAtMostFor = "1200m")
+ @SchedulerLock(name = "tvrBatchJob", lockAtLeastFor = "${batch.system.scheduled.routines.lockAtLeastFor}", lockAtMostFor = "${batch.system.scheduled.routines.lockAtMostFor}")
public void runTranscriptVerificationReportProcess() {
LOGGER.info(BATCH_STARTED);
+ LockAssert.assertLocked();
JobParametersBuilder builder = new JobParametersBuilder();
builder.addLong(TIME, System.currentTimeMillis()).toJobParameters();
builder.addString(JOB_TRIGGER, BATCH_TRIGGER);
@@ -106,9 +110,10 @@ public void runTranscriptVerificationReportProcess() {
}
@Scheduled(cron = "${batch.distrun.cron}")
- @SchedulerLock(name = "DistributionBatchJob", lockAtLeastFor = "10s", lockAtMostFor = "120m")
+ @SchedulerLock(name = "DistributionBatchJob", lockAtLeastFor = "PT10S", lockAtMostFor = "PT120M")
public void runMonthlyDistributionProcess() {
LOGGER.info(BATCH_STARTED);
+ LockAssert.assertLocked();
JobParametersBuilder builder = new JobParametersBuilder();
builder.addLong(TIME, System.currentTimeMillis()).toJobParameters();
builder.addString(JOB_TRIGGER, BATCH_TRIGGER);
@@ -126,9 +131,10 @@ public void runMonthlyDistributionProcess() {
}
@Scheduled(fixedDelayString = "PT30M")
- @SchedulerLock(name = "userScheduledBatchJobRefresher", lockAtLeastFor = "10s", lockAtMostFor = "5m")
+ @SchedulerLock(name = "userScheduledBatchJobRefresher", lockAtLeastFor = "PT10S", lockAtMostFor = "PT5M")
public void refreshUserScheduledQueue() {
LOGGER.info(BATCH_STARTED);
+ LockAssert.assertLocked();
JobParametersBuilder builder = new JobParametersBuilder();
builder.addLong(TIME, System.currentTimeMillis()).toJobParameters();
try {
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/TaskSchedulerConfig.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/TaskSchedulerConfig.java
index 2c4d823e..fe5f2158 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/TaskSchedulerConfig.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/config/TaskSchedulerConfig.java
@@ -36,7 +36,8 @@ public LockableTaskScheduler getScheduler() {
LockManager lockManager = new DefaultLockManager(lockProvider, lockConfigurationExtractor);
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
- scheduler.setThreadNamePrefix("UserScheduledTaskScheduler");
+ scheduler.setPoolSize(30);
+ scheduler.setThreadNamePrefix("UserScheduledTask-");
scheduler.initialize();
return new LockableTaskScheduler(scheduler, lockManager);
}
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/controller/JobLauncherController.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/controller/JobLauncherController.java
index 6b1f195f..1b72e427 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/controller/JobLauncherController.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/controller/JobLauncherController.java
@@ -466,6 +466,14 @@ public ResponseEntity launchMonthlyDistributionRunJob()
@Operation(summary = "Run Distribution Runs", description = "Run Distribution Runs", tags = { "Distribution" })
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"),@ApiResponse(responseCode = "500", description = "Internal Server Error")})
public ResponseEntity launchDistributionRunJob() {
+ return launchDistributionRunJob(null);
+ }
+
+ @PostMapping(EducGradBatchGraduationApiConstants.EXECUTE_DIS_RUN_BATCH_JOB)
+ @PreAuthorize(PermissionsConstants.RUN_GRAD_ALGORITHM)
+ @Operation(summary = "Run Distribution Runs", description = "Run Distribution Runs", tags = { "Distribution" })
+ @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"),@ApiResponse(responseCode = "500", description = "Internal Server Error")})
+ public ResponseEntity launchDistributionRunJob(@RequestBody StudentSearchRequest request) {
logger.debug("launchDistributionRunJob");
JobParametersBuilder builder = new JobParametersBuilder();
builder.addLong(TIME, System.currentTimeMillis()).toJobParameters();
@@ -473,6 +481,9 @@ public ResponseEntity launchDistributionRunJob() {
builder.addString(JOB_TRIGGER, MANUAL);
builder.addString(JOB_TYPE, DISTRUN);
try {
+ if(request != null) {
+ builder.addString(SEARCH_REQUEST, jsonTransformer.marshall(request));
+ }
JobExecution jobExecution = asyncJobLauncher.run(jobRegistry.getJob("DistributionBatchJob"), builder.toJobParameters());
ExecutionContext jobContext = jobExecution.getExecutionContext();
DistributionSummaryDTO summaryDTO = (DistributionSummaryDTO)jobContext.get(DISDTO);
@@ -483,7 +494,7 @@ public ResponseEntity launchDistributionRunJob() {
summaryDTO.setBatchId(jobExecution.getId());
return ResponseEntity.ok(summaryDTO);
} catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
- | JobParametersInvalidException | NoSuchJobException e) {
+ | JobParametersInvalidException | NoSuchJobException e) {
DistributionSummaryDTO summaryDTO = new DistributionSummaryDTO();
summaryDTO.setException(e.getLocalizedMessage());
return ResponseEntity.status(500).body(summaryDTO);
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/entity/BatchJobExecutionEntity.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/entity/BatchJobExecutionEntity.java
index c8d02118..ea51c85a 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/entity/BatchJobExecutionEntity.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/entity/BatchJobExecutionEntity.java
@@ -44,8 +44,9 @@ public class BatchJobExecutionEntity {
@Column(name = "EXIT_MESSAGE", length = 2500)
private String exitMessage;
- @Column(name = "LAST_UPDATED")
- private Instant lastUpdated;
+ @Column(name = "LAST_UPDATED", nullable = true)
+ @Temporal(TemporalType.TIMESTAMP)
+ private LocalDateTime lastUpdated;
@Column(name = "JOB_CONFIGURATION_LOCATION", length = 2500)
private String jobConfigurationLocation;
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/entity/BatchStepExecutionEntity.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/entity/BatchStepExecutionEntity.java
index eefb4f1e..6b01c9e8 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/entity/BatchStepExecutionEntity.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/entity/BatchStepExecutionEntity.java
@@ -1,12 +1,9 @@
package ca.bc.gov.educ.api.batchgraduation.entity;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Id;
-import jakarta.persistence.Table;
+import jakarta.persistence.*;
import lombok.Data;
-import java.time.Instant;
+import java.time.LocalDateTime;
@Data
@Entity
@@ -27,10 +24,12 @@ public class BatchStepExecutionEntity {
private String stepName;
@Column(name = "START_TIME")
- private Instant startTime = Instant.now();
+ @Temporal(TemporalType.TIMESTAMP)
+ private LocalDateTime startTime = LocalDateTime.now();
@Column(name = "END_TIME")
- private Instant endTime;
+ @Temporal(TemporalType.TIMESTAMP)
+ private LocalDateTime endTime;
@Column(name = "STATUS", length = 10)
private String status;
@@ -66,9 +65,11 @@ public class BatchStepExecutionEntity {
private String exitMessage;
@Column(name = "LAST_UPDATED")
- private Instant lastUpdated = Instant.now();
+ @Temporal(TemporalType.TIMESTAMP)
+ private LocalDateTime lastUpdated = LocalDateTime.now();
@Column(name = "CREATE_TIME")
- private Instant createTime = Instant.now();
+ @Temporal(TemporalType.TIMESTAMP)
+ private LocalDateTime createTime = LocalDateTime.now();
}
\ No newline at end of file
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/listener/UserReqBlankDistributionRunCompletionNotificationListener.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/listener/UserReqBlankDistributionRunCompletionNotificationListener.java
index 8360a520..7dd9a14c 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/listener/UserReqBlankDistributionRunCompletionNotificationListener.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/listener/UserReqBlankDistributionRunCompletionNotificationListener.java
@@ -77,14 +77,16 @@ public void afterJob(JobExecution jobExecution) {
BlankDistributionSummaryDTO finalSummaryDTO = summaryDTO;
summaryDTO.getCredentialCountMap().forEach((key, value) -> LOGGER.info(" {} count : {}", key, finalSummaryDTO.getCredentialCountMap().get(key)));
+ StudentSearchRequest studentSearchRequestObject = (StudentSearchRequest)jsonTransformer.unmarshall(studentSearchRequest, StudentSearchRequest.class);
+
ResponseObj obj = restUtils.getTokenResponseObject();
LOGGER.info("Starting Report Process --------------------------------------------------------------------------");
- processGlobalList(credentialType,summaryDTO.getGlobalList(),jobExecutionId,summaryDTO.getMapDist(),obj.getAccess_token(),localDownLoad,properName);
+ processGlobalList(studentSearchRequestObject, credentialType,summaryDTO.getGlobalList(),jobExecutionId,summaryDTO.getMapDist(),obj.getAccess_token(),localDownLoad,properName);
LOGGER.info(LOG_SEPARATION);
}
}
- private void processGlobalList(String credentialType, List cList, Long batchId, Map mapDist, String accessToken,String localDownload,String properName) {
+ private void processGlobalList(StudentSearchRequest studentSearchRequest , String credentialType, List cList, Long batchId, Map mapDist, String accessToken,String localDownload,String properName) {
List uniqueSchoolList = cList.stream().map(BlankCredentialDistribution::getSchoolOfRecord).distinct().collect(Collectors.toList());
uniqueSchoolList.forEach(usl->{
List yed4List = new ArrayList<>();
@@ -109,7 +111,7 @@ private void processGlobalList(String credentialType, List schoolOfRecords;
private List credentialTypeCode;
+ private String user;
+ private Address address;
private int quantity;
String localDownload;
}
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/model/StudentSearchRequest.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/model/StudentSearchRequest.java
index 9f502e42..8bff9ac9 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/model/StudentSearchRequest.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/model/StudentSearchRequest.java
@@ -26,6 +26,7 @@ public class StudentSearchRequest implements Serializable {
private List studentIDs;
private String user;
+ private Address address;
@JsonFormat(pattern = "yyyy-MM-dd")
Date gradDateFrom;
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/BasePartitioner.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/BasePartitioner.java
index bba796f7..8c8fd18b 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/BasePartitioner.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/BasePartitioner.java
@@ -226,16 +226,19 @@ void filterByStudentSearchRequest(List eligibleSt
useFilterSchoolDistricts.add(school.getMincode());
}
}
- eligibleStudentSchoolDistricts.removeIf(scr->!useFilterSchoolDistricts.contains(scr.getSchoolOfRecord()));
+ eligibleStudentSchoolDistricts.removeIf(scr->StringUtils.isNotBlank(scr.getSchoolOfRecord()) && !useFilterSchoolDistricts.contains(scr.getSchoolOfRecord()));
}
if(searchRequest != null && searchRequest.getDistricts() != null && !searchRequest.getDistricts().isEmpty()) {
- eligibleStudentSchoolDistricts.removeIf(scr->!searchRequest.getDistricts().contains(StringUtils.substring(scr.getSchoolOfRecord(), 0, 3)));
+ eligibleStudentSchoolDistricts.removeIf(scr->StringUtils.isNotBlank(scr.getSchoolOfRecord()) && !searchRequest.getDistricts().contains(StringUtils.substring(scr.getSchoolOfRecord(), 0, 3)));
}
if(searchRequest != null && searchRequest.getSchoolOfRecords() != null && !searchRequest.getSchoolOfRecords().isEmpty()) {
- eligibleStudentSchoolDistricts.removeIf(scr->!searchRequest.getSchoolOfRecords().contains(scr.getSchoolOfRecord()));
+ eligibleStudentSchoolDistricts.removeIf(scr->StringUtils.isNotBlank(scr.getSchoolOfRecord()) && !searchRequest.getSchoolOfRecords().contains(scr.getSchoolOfRecord()));
+ }
+ if(searchRequest != null && searchRequest.getStudentIDs() != null && !searchRequest.getStudentIDs().isEmpty()) {
+ eligibleStudentSchoolDistricts.removeIf(scr->scr.getStudentID() != null && !searchRequest.getStudentIDs().contains(scr.getStudentID()));
}
if(searchRequest != null && searchRequest.getPens() != null && !searchRequest.getPens().isEmpty()) {
- eligibleStudentSchoolDistricts.removeIf(scr->!searchRequest.getPens().contains(scr.getPen()));
+ eligibleStudentSchoolDistricts.removeIf(scr->StringUtils.isNotBlank(scr.getPen()) && !searchRequest.getPens().contains(scr.getPen()));
}
}
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunPartitioner.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunPartitioner.java
index 95b565c3..8580c37c 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunPartitioner.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunPartitioner.java
@@ -1,7 +1,6 @@
package ca.bc.gov.educ.api.batchgraduation.reader;
import ca.bc.gov.educ.api.batchgraduation.model.DistributionDataParallelDTO;
-import ca.bc.gov.educ.api.batchgraduation.model.ResponseObj;
import ca.bc.gov.educ.api.batchgraduation.model.StudentCredentialDistribution;
import ca.bc.gov.educ.api.batchgraduation.service.ParallelDataFetch;
import org.slf4j.Logger;
@@ -12,14 +11,17 @@
import org.springframework.beans.factory.annotation.Value;
import reactor.core.publisher.Mono;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/**
* Monthly Distribution Partitioner
*/
public class DistributionRunPartitioner extends BasePartitioner {
- private static final Logger LOGGER = LoggerFactory.getLogger(DistributionRunPartitioner.class);
+ private static final Logger logger = LoggerFactory.getLogger(DistributionRunPartitioner.class);
@Value("#{stepExecution.jobExecution}")
JobExecution context;
@@ -29,23 +31,18 @@ public class DistributionRunPartitioner extends BasePartitioner {
@Override
public Map partition(int gridSize) {
- ResponseObj res = restUtils.getTokenResponseObject();
- String accessToken = null;
- if (res != null) {
- accessToken = res.getAccess_token();
- }
// Clean up existing reports before running new one
- LOGGER.debug("Delete School Reports for Monthly Distribution");
+ logger.debug("Delete School Reports for Monthly Distribution");
long startTime = System.currentTimeMillis();
restUtils.deleteSchoolReportRecord("", "ADDRESS_LABEL_SCHL", restUtils.getAccessToken());
long endTime = System.currentTimeMillis();
long diff = (endTime - startTime)/1000;
- LOGGER.debug("Old School Reports deleted in {} sec", diff);
+ logger.debug("Old School Reports deleted in {} sec", diff);
startTime = System.currentTimeMillis();
- LOGGER.debug("Retrieve students for Monthly Distribution");
- Mono parallelDTOMono = parallelDataFetch.fetchDistributionRequiredData(accessToken);
+ logger.debug("Retrieve students for Monthly Distribution");
+ Mono parallelDTOMono = parallelDataFetch.fetchDistributionRequiredData(restUtils.getAccessToken());
DistributionDataParallelDTO parallelDTO = parallelDTOMono.block();
List credentialList = new ArrayList<>();
if(parallelDTO != null) {
@@ -54,20 +51,14 @@ public Map partition(int gridSize) {
}
endTime = System.currentTimeMillis();
diff = (endTime - startTime)/1000;
- LOGGER.debug("Total {} eligible StudentCredentialDistributions found in {} sec", credentialList.size(), diff);
+ logger.debug("Total {} eligible StudentCredentialDistributions found in {} sec", credentialList.size(), diff);
+ filterByStudentSearchRequest(credentialList);
if(!credentialList.isEmpty()) {
- LOGGER.debug("Total size of credential list: {}", credentialList.size());
- // Filter deceased students out
- List deceasedIDs = restUtils.getDeceasedStudentIDs(credentialList.stream().map(StudentCredentialDistribution::getStudentID).distinct().toList(), restUtils.getAccessToken());
- if (!deceasedIDs.isEmpty()) {
- LOGGER.debug("Deceased students: {}", deceasedIDs.size());
- credentialList.removeIf(cr -> deceasedIDs.contains(cr.getStudentID()));
- LOGGER.debug("Revised size of credential list: {}", credentialList.size());
- }
+ filterOutDeceasedStudents(credentialList);
updateBatchJobHistory(createBatchJobHistory(), (long) credentialList.size());
return getStringExecutionContextMap(gridSize, credentialList, null);
}
- LOGGER.info("No Credentials Found for Processing");
+ logger.info("No Credentials Found for Processing");
return new HashMap<>();
}
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunPartitionerBlankUserReq.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunPartitionerBlankUserReq.java
index c97ac3e1..9c254db5 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunPartitionerBlankUserReq.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunPartitionerBlankUserReq.java
@@ -75,6 +75,7 @@ private List getRecordsForBlankUserReqDisRun(BlankC
bcd.setQuantity(req.getQuantity());
bcd.setSchoolOfRecord(sch);
bcd.setCredentialTypeCode(ctc);
+ bcd.setAddress(req.getAddress());
blankList.add(bcd);
}
});
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunSupplementalPartitioner.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunSupplementalPartitioner.java
index 1c54319b..7d500b41 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunSupplementalPartitioner.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/reader/DistributionRunSupplementalPartitioner.java
@@ -11,10 +11,7 @@
import org.springframework.beans.factory.annotation.Value;
import reactor.core.publisher.Mono;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
public class DistributionRunSupplementalPartitioner extends BasePartitioner {
@@ -31,28 +28,22 @@ public Map partition(int gridSize) {
logger.debug("Delete School Reports for Supplemental Distribution");
long startTime = System.currentTimeMillis();
- String accessToken = restUtils.getAccessToken();
// Clean up existing reports before running new one
- restUtils.deleteSchoolReportRecord("", "ADDRESS_LABEL_SCHL", accessToken);
- restUtils.deleteSchoolReportRecord("", "DISTREP_SC", accessToken);
+ restUtils.deleteSchoolReportRecord("", "ADDRESS_LABEL_SCHL", restUtils.getAccessToken());
+ restUtils.deleteSchoolReportRecord("", "DISTREP_SC", restUtils.getAccessToken());
long endTime = System.currentTimeMillis();
long diff = (endTime - startTime)/1000;
logger.debug("Old School Reports deleted in {} sec", diff);
startTime = System.currentTimeMillis();
logger.debug("Retrieve students for Supplemental Distribution");
- Mono parallelDTOMono = parallelDataFetch.fetchDistributionRequiredDataYearly(accessToken);
- DistributionDataParallelDTO parallelDTO = parallelDTOMono.block();
- List eligibleStudentSchoolDistricts = new ArrayList<>();
- if(parallelDTO != null) {
- eligibleStudentSchoolDistricts.addAll(parallelDTO.transcriptList());
- eligibleStudentSchoolDistricts.addAll(parallelDTO.certificateList());
- }
+ List eligibleStudentSchoolDistricts = parallelDataFetch.fetchStudentCredentialsDistributionDataYearly();
endTime = System.currentTimeMillis();
diff = (endTime - startTime)/1000;
logger.debug("Total {} eligible StudentCredentialDistributions found in {} sec", eligibleStudentSchoolDistricts.size(), diff);
filterByStudentSearchRequest(eligibleStudentSchoolDistricts);
if(!eligibleStudentSchoolDistricts.isEmpty()) {
+ filterOutDeceasedStudents(eligibleStudentSchoolDistricts);
updateBatchJobHistory(createBatchJobHistory(), (long) eligibleStudentSchoolDistricts.size());
return getStringExecutionContextMap(gridSize, eligibleStudentSchoolDistricts, null);
}
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/repository/BatchStepExecutionRepository.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/repository/BatchStepExecutionRepository.java
new file mode 100644
index 00000000..0d4adcfa
--- /dev/null
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/repository/BatchStepExecutionRepository.java
@@ -0,0 +1,14 @@
+package ca.bc.gov.educ.api.batchgraduation.repository;
+
+import ca.bc.gov.educ.api.batchgraduation.entity.BatchStepExecutionEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface BatchStepExecutionRepository extends JpaRepository {
+
+ List findByJobExecutionIdOrderByEndTimeDesc(Long jobExecutionId);
+
+}
diff --git a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/service/GradDashboardService.java b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/service/GradDashboardService.java
index 126f1fea..30f55394 100644
--- a/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/service/GradDashboardService.java
+++ b/api/src/main/java/ca/bc/gov/educ/api/batchgraduation/service/GradDashboardService.java
@@ -2,20 +2,17 @@
import ca.bc.gov.educ.api.batchgraduation.entity.*;
import ca.bc.gov.educ.api.batchgraduation.model.*;
-import ca.bc.gov.educ.api.batchgraduation.repository.BatchGradAlgorithmJobHistoryRepository;
-import ca.bc.gov.educ.api.batchgraduation.repository.BatchGradAlgorithmStudentRepository;
-import ca.bc.gov.educ.api.batchgraduation.repository.BatchJobExecutionRepository;
-import ca.bc.gov.educ.api.batchgraduation.repository.BatchProcessingRepository;
+import ca.bc.gov.educ.api.batchgraduation.repository.*;
import ca.bc.gov.educ.api.batchgraduation.rest.RestUtils;
import ca.bc.gov.educ.api.batchgraduation.transformer.BatchGradAlgorithmJobHistoryTransformer;
import ca.bc.gov.educ.api.batchgraduation.transformer.BatchProcessingTransformer;
-import org.apache.commons.lang3.time.DateUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@@ -23,10 +20,13 @@
@Service
public class GradDashboardService extends GradService {
+ private static final String JOB_STATUS_STARTED = BatchStatusEnum.STARTED.name();
+
private final BatchGradAlgorithmJobHistoryRepository batchGradAlgorithmJobHistoryRepository;
private final BatchGradAlgorithmStudentRepository batchGradAlgorithmStudentRepository;
private final BatchGradAlgorithmJobHistoryTransformer batchGradAlgorithmJobHistoryTransformer;
private final BatchJobExecutionRepository batchJobExecutionRepository;
+ private final BatchStepExecutionRepository batchStepExecutionRepository;
private final BatchProcessingTransformer batchProcessingTransformer;
private final BatchProcessingRepository batchProcessingRepository;
private final RestUtils restUtils;
@@ -34,13 +34,16 @@ public class GradDashboardService extends GradService {
public GradDashboardService(BatchGradAlgorithmJobHistoryRepository batchGradAlgorithmJobHistoryRepository,
BatchGradAlgorithmJobHistoryTransformer batchGradAlgorithmJobHistoryTransformer,
RestUtils restUtils,
- BatchJobExecutionRepository batchJobExecutionRepository,BatchProcessingRepository batchProcessingRepository,BatchProcessingTransformer batchProcessingTransformer,
+ BatchJobExecutionRepository batchJobExecutionRepository,
+ BatchStepExecutionRepository batchStepExecutionRepository,
+ BatchProcessingRepository batchProcessingRepository,BatchProcessingTransformer batchProcessingTransformer,
BatchGradAlgorithmStudentRepository batchGradAlgorithmStudentRepository) {
this.batchGradAlgorithmJobHistoryRepository = batchGradAlgorithmJobHistoryRepository;
this.batchGradAlgorithmJobHistoryTransformer = batchGradAlgorithmJobHistoryTransformer;
this.batchProcessingTransformer = batchProcessingTransformer;
this.batchGradAlgorithmStudentRepository = batchGradAlgorithmStudentRepository;
this.batchJobExecutionRepository = batchJobExecutionRepository;
+ this.batchStepExecutionRepository = batchStepExecutionRepository;
this.batchProcessingRepository = batchProcessingRepository;
this.restUtils = restUtils;
}
@@ -50,7 +53,7 @@ public GradDashboard getDashboardInfo() {
start();
GradDashboard gradDash = new GradDashboard();
List infoDetailsList= batchGradAlgorithmJobHistoryTransformer.transformToDTO(batchGradAlgorithmJobHistoryRepository.findAll());
- infoDetailsList = infoDetailsList.stream().map(this::handleDeadJob).collect(Collectors.toList());
+ infoDetailsList = infoDetailsList.stream().map(this::handleDeadJob).map(this::handleFrozenJob).collect(Collectors.toList());
infoDetailsList.sort(Comparator.comparing(BatchGradAlgorithmJobHistory::getStartTime).reversed());
if(!infoDetailsList.isEmpty()) {
BatchGradAlgorithmJobHistory info = infoDetailsList.get(0);
@@ -144,30 +147,55 @@ public Optional findBatchProcessing(String jobType) {
return batchProcessingRepository.findByJobType(jobType);
}
+ /**
+ * If any batch jobs have "STARTED" status more than 3 days(72 hours), then treat it as FAILED job
+ */
@Transactional
public BatchGradAlgorithmJobHistory handleDeadJob(BatchGradAlgorithmJobHistory batchJobHistory) {
- if ("STARTED".equalsIgnoreCase(batchJobHistory.getStatus())
- && batchJobHistory.getEndTime() == null) {
- Integer jobExecutionId = batchJobHistory.getJobExecutionId();
+ if (JOB_STATUS_STARTED.equalsIgnoreCase(batchJobHistory.getStatus()) && batchJobHistory.getEndTime() == null) {
+ LocalDateTime now = LocalDateTime.now();
+ Duration duration = Duration.between(batchJobHistory.getStartTime(), now);
+ long hours = duration.getSeconds() / 3600;
+ if (hours > 72) {
+ updateBatchJobStatus(batchJobHistory, BatchStatusEnum.FAILED);
+ }
+ }
- Date now = new Date(System.currentTimeMillis());
- LocalDateTime deadline = ca.bc.gov.educ.api.batchgraduation.util.DateUtils.toLocalDateTime(DateUtils.addDays(now, -3));
+ return batchJobHistory;
+ }
- if (batchJobHistory.getStartTime().isBefore(deadline)) {
- Optional optional = batchJobExecutionRepository.findById(jobExecutionId.longValue());
- if (optional.isPresent()) {
- BatchJobExecutionEntity batchJobExecution = optional.get();
- if ("UNKNOWN".equalsIgnoreCase(batchJobExecution.getExitCode())
- || BatchStatusEnum.FAILED.toString().equalsIgnoreCase(batchJobExecution.getExitCode()) ) {
- BatchGradAlgorithmJobHistoryEntity entity = batchGradAlgorithmJobHistoryTransformer.transformToEntity(batchJobHistory);
- entity.setStatus(BatchStatusEnum.FAILED.toString());
- batchGradAlgorithmJobHistoryRepository.save(entity);
- batchJobHistory.setStatus(BatchStatusEnum.FAILED.toString());
- }
- }
+ @Transactional
+ public BatchGradAlgorithmJobHistory handleFrozenJob(BatchGradAlgorithmJobHistory batchJobHistory) {
+ if (JOB_STATUS_STARTED.equalsIgnoreCase(batchJobHistory.getStatus()) && batchJobHistory.getEndTime() == null) {
+ Integer jobExecutionId = batchJobHistory.getJobExecutionId();
+ if (isFrozen(jobExecutionId.longValue())) {
+ updateBatchJobStatus(batchJobHistory, BatchStatusEnum.FAILED);
}
}
-
return batchJobHistory;
}
+
+ /**
+ * If last updated time is frozen more than 5 hours for all of "STARTED" steps, then treat it as FAILED job
+ */
+ private boolean isFrozen(Long jobExecutionId) {
+ List steps = batchStepExecutionRepository.findByJobExecutionIdOrderByEndTimeDesc(jobExecutionId);
+ LocalDateTime now = LocalDateTime.now();
+ boolean frozenStepFound = false;
+ for (BatchStepExecutionEntity step : steps) {
+ if (step.getStepName().contains("partition") && JOB_STATUS_STARTED.equalsIgnoreCase(step.getStatus())) {
+ Duration duration = Duration.between(step.getLastUpdated(), now);
+ long hours = duration.getSeconds() / 3600;
+ frozenStepFound = hours > 5;
+ }
+ }
+ return frozenStepFound;
+ }
+
+ private void updateBatchJobStatus(BatchGradAlgorithmJobHistory batchJobHistory, BatchStatusEnum batchStatus) {
+ BatchGradAlgorithmJobHistoryEntity entity = batchGradAlgorithmJobHistoryTransformer.transformToEntity(batchJobHistory);
+ entity.setStatus(batchStatus.toString());
+ batchGradAlgorithmJobHistoryRepository.save(entity);
+ batchJobHistory.setStatus(BatchStatusEnum.FAILED.toString());
+ }
}
diff --git a/api/src/main/resources/application.yaml b/api/src/main/resources/application.yaml
index 7acc1f1b..4014ad4e 100644
--- a/api/src/main/resources/application.yaml
+++ b/api/src/main/resources/application.yaml
@@ -153,6 +153,11 @@ batch:
jobs:
lockAtLeastFor: ${CRON_USER_SCHEDULED_JOBS_LOCK_AT_LEAST_FOR}
lockAtMostFor: ${CRON_USER_SCHEDULED_JOBS_LOCK_AT_MOST_FOR}
+ system:
+ scheduled:
+ routines:
+ lockAtLeastFor: ${CRON_SYSTEM_SCHEDULED_ROUTINES_LOCK_AT_LEAST_FOR}
+ lockAtMostFor: ${CRON_SYSTEM_SCHEDULED_ROUTINES_LOCK_AT_MOST_FOR}
#Endpoints
endpoint:
diff --git a/api/src/test/java/ca/bc/gov/educ/api/batchgraduation/service/GradDashboardServiceTest.java b/api/src/test/java/ca/bc/gov/educ/api/batchgraduation/service/GradDashboardServiceTest.java
index 980b0ea4..8be796a2 100644
--- a/api/src/test/java/ca/bc/gov/educ/api/batchgraduation/service/GradDashboardServiceTest.java
+++ b/api/src/test/java/ca/bc/gov/educ/api/batchgraduation/service/GradDashboardServiceTest.java
@@ -1,14 +1,8 @@
package ca.bc.gov.educ.api.batchgraduation.service;
-import ca.bc.gov.educ.api.batchgraduation.entity.BatchGradAlgorithmJobHistoryEntity;
-import ca.bc.gov.educ.api.batchgraduation.entity.BatchGradAlgorithmStudentEntity;
-import ca.bc.gov.educ.api.batchgraduation.entity.BatchJobExecutionEntity;
-import ca.bc.gov.educ.api.batchgraduation.entity.BatchProcessingEntity;
+import ca.bc.gov.educ.api.batchgraduation.entity.*;
import ca.bc.gov.educ.api.batchgraduation.model.*;
-import ca.bc.gov.educ.api.batchgraduation.repository.BatchGradAlgorithmJobHistoryRepository;
-import ca.bc.gov.educ.api.batchgraduation.repository.BatchGradAlgorithmStudentRepository;
-import ca.bc.gov.educ.api.batchgraduation.repository.BatchJobExecutionRepository;
-import ca.bc.gov.educ.api.batchgraduation.repository.BatchProcessingRepository;
+import ca.bc.gov.educ.api.batchgraduation.repository.*;
import ca.bc.gov.educ.api.batchgraduation.rest.RestUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.junit.Test;
@@ -48,6 +42,9 @@ public class GradDashboardServiceTest {
@MockBean
BatchJobExecutionRepository batchJobExecutionRepository;
+ @MockBean
+ BatchStepExecutionRepository batchStepExecutionRepository;
+
@MockBean
BatchProcessingRepository batchProcessingRepository;
@@ -86,7 +83,7 @@ public void testGetDashboardInfo_whenStartedDate_isOlderThan3Days_thenUpdateStat
hist.setExpectedStudentsProcessed(20L);
hist.setJobExecutionId(121L);
Date today = new Date(System.currentTimeMillis());
- Date startedDateTime = DateUtils.addDays(today, -3);
+ Date startedDateTime = DateUtils.addDays(today, -4);
hist.setStartTime(ca.bc.gov.educ.api.batchgraduation.util.DateUtils.toLocalDateTime(startedDateTime));
hist.setStatus("STARTED");
list.add(hist);
@@ -109,6 +106,48 @@ public void testGetDashboardInfo_whenStartedDate_isOlderThan3Days_thenUpdateStat
}
+ @Test
+ public void testGetDashboardInfo_whenLastUpdatedDate_isOlderThan5hours_thenUpdateStatusAsFailed() {
+
+ List list = new ArrayList<>();
+ BatchGradAlgorithmJobHistoryEntity hist = new BatchGradAlgorithmJobHistoryEntity();
+ hist.setId(new UUID(1,1));
+ hist.setExpectedStudentsProcessed(20L);
+ hist.setJobExecutionId(121L);
+ Date today = new Date(System.currentTimeMillis());
+ Date startedDateTime = DateUtils.addDays(today, -1);
+ hist.setStartTime(ca.bc.gov.educ.api.batchgraduation.util.DateUtils.toLocalDateTime(startedDateTime));
+ hist.setStatus("STARTED");
+ list.add(hist);
+
+ BatchJobExecutionEntity batchJobExecution = new BatchJobExecutionEntity();
+ batchJobExecution.setJobExecutionId(hist.getJobExecutionId());
+ batchJobExecution.setId(Long.valueOf("123"));
+ batchJobExecution.setStatus("STARTED");
+ batchJobExecution.setStartTime(hist.getStartTime());
+
+ BatchStepExecutionEntity step = new BatchStepExecutionEntity();
+ step.setStepName("test-partition12");
+ step.setJobExecutionId(hist.getJobExecutionId());
+ step.setId(Long.valueOf("123"));
+ step.setStatus("STARTED");
+ step.setStartTime(ca.bc.gov.educ.api.batchgraduation.util.DateUtils.toLocalDateTime(startedDateTime));
+ Date lastUpdatedDateTime = DateUtils.addHours(today, -6);
+ step.setLastUpdated(ca.bc.gov.educ.api.batchgraduation.util.DateUtils.toLocalDateTime(lastUpdatedDateTime));
+ batchJobExecution.setStartTime(hist.getStartTime());
+
+ when(batchGradAlgorithmJobHistoryRepository.findAll()).thenReturn(list);
+ when(batchJobExecutionRepository.findById(hist.getJobExecutionId())).thenReturn(Optional.of(batchJobExecution));
+ when(batchStepExecutionRepository.findByJobExecutionIdOrderByEndTimeDesc(hist.getJobExecutionId())).thenReturn(List.of(step));
+
+ GradDashboard dash = gradDashboardService.getDashboardInfo();
+ assertThat(dash).isNotNull();
+ assertThat(dash.getTotalBatchRuns()).isEqualTo(1);
+ assertThat(dash.getBatchInfoList()).isNotEmpty();
+ assertThat(dash.getBatchInfoList().get(0).getStatus()).isEqualTo("FAILED");
+
+ }
+
@Test
public void testgetProcessingList() {
diff --git a/api/src/test/resources/application.yaml b/api/src/test/resources/application.yaml
index 0fb49899..67671136 100644
--- a/api/src/test/resources/application.yaml
+++ b/api/src/test/resources/application.yaml
@@ -82,6 +82,11 @@ batch:
jobs:
lockAtLeastFor: 10
lockAtMostFor: 180
+ system:
+ scheduled:
+ routines:
+ lockAtLeastFor: PT1M
+ lockAtMostFor: PT600M
#Endpoints
endpoint: