Skip to content

Commit

Permalink
GRAD2-2822: School Report Regeneration Process - Backend Changes
Browse files Browse the repository at this point in the history
  • Loading branch information
kamal-mohammed committed Sep 6, 2024
1 parent 9838576 commit e5e7552
Show file tree
Hide file tree
Showing 12 changed files with 374 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,66 @@ public Job certRegenBatchJob(JobRepository jobRepository, PlatformTransactionMan
.build();
}

/**
* Regenerate School Reports
*/

@Bean
@StepScope
public RegenerateSchoolReportsPartitioner partitionerSchoolReportsRegen() {
return new RegenerateSchoolReportsPartitioner();
}

@Bean
@StepScope
public RegenerateSchoolReportsReader itemReaderSchoolReportsRegen() {
return new RegenerateSchoolReportsReader();
}

@Bean
@StepScope
public RegenerateSchoolReportsProcessor itemProcessorSchoolReportsRegen() { return new RegenerateSchoolReportsProcessor(); }

@Bean
@StepScope
public RegenerateSchoolReportsWriter itemWriterSchoolReportsRegen() {
return new RegenerateSchoolReportsWriter();
}

@Bean
public Step schoolReportsRegenJobStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, SkipSQLTransactionExceptionsListener skipListener) {
return new StepBuilder("schoolReportsRegenJobStep", jobRepository)
.<List<String>, List<String>>chunk(1, transactionManager)
.reader(itemReaderSchoolReportsRegen())
.processor(itemProcessorSchoolReportsRegen())
.writer(itemWriterSchoolReportsRegen())
.faultTolerant()
.listener(skipListener)
.skip(Exception.class)
.build();
}

@Bean
public Step masterStepSchoolReportsRegen(JobRepository jobRepository, PlatformTransactionManager transactionManager, EducGradBatchGraduationApiConstants constants, SkipSQLTransactionExceptionsListener skipListener) {
return new StepBuilder("masterStepSchoolReportsRegen", jobRepository)
.partitioner(schoolReportsRegenJobStep(jobRepository, transactionManager, skipListener).getName(), partitionerSchoolReportsRegen())
.step(schoolReportsRegenJobStep(jobRepository, transactionManager, skipListener))
.gridSize(constants.getNumberOfPartitions())
.taskExecutor(taskExecutor())
.build();
}

@Bean(name="schoolReportsRegenBatchJob")
public Job schoolReportsRegenBatchJob(JobRepository jobRepository, PlatformTransactionManager transactionManager, RegenSchoolReportsCompletionNotificationListener listener, SkipSQLTransactionExceptionsListener skipListener, EducGradBatchGraduationApiConstants constants) {
return new JobBuilder("schoolReportsRegenBatchJob", jobRepository)
.incrementer(new RunIdIncrementer())
.listener(listener)
.start(masterStepSchoolReportsRegen(jobRepository, transactionManager,constants, skipListener))
.on("*")
.end().build()
.build();
}

/**
* Create Graduation Status snapshot for EDW
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -58,14 +57,11 @@ public class JobLauncherController {
private static final String TVRRUN = "TVRRUN";
private static final String REGALG = "REGALG";
private static final String CERT_REGEN = "CERT_REGEN";

private static final String SCHL_RPT_REGEN = "SCHL_RPT_REGEN";
private static final String EDW_SNAPSHOT = "EDW_SNAPSHOT";

private static final String ARCHIVE_SCHOOL_REPORTS = "ARC_SCH_REPORTS";
private static final String DELETE_STUDENT_REPORTS = "TVR_DELETE";

private static final String ARCHIVE_STUDENTS = "ARC_STUDENTS";

private static final String RERUN_ALL = "RERUN_ALL";
private static final String RERUN_FAILED = "RERUN_FAILED";
private static final String DISTRUN = "DISTRUN";
Expand All @@ -83,16 +79,12 @@ public class JobLauncherController {
private static final String TVR_BATCH_JOB = "tvrBatchJob";
private static final String SPECIAL_GRADUATION_BATCH_JOB = "SpecialGraduationBatchJob";
private static final String SPECIAL_TVR_RUN_BATCH_JOB = "SpecialTvrRunBatchJob";

private static final String CERTIFICATE_REGENERATION_BATCH_JOB = "certRegenBatchJob";

private static final String EDW_SNAPSHOT_BATCH_JOB = "edwSnapshotBatchJob";

private static final String ARCHIVE_SCHOOL_REPORTS_BATCH_JOB = "archiveSchoolReportsBatchJob";

private static final String DELETE_STUDENT_REPORTS_BATCH_JOB = "deleteStudentReportsBatchJob";

private static final String ARCHIVE_STUDENTS_BATCH_JOB = "archiveStudentsBatchJob";
private static final String REGENERATE_SCHOOL_REPORTS_BATCH_JOB = "schoolReportsRegenBatchJob";

private final JobLauncher jobLauncher;
private final JobLauncher asyncJobLauncher;
Expand Down Expand Up @@ -490,7 +482,7 @@ public ResponseEntity<Boolean> launchRegenerateSchoolReports(@PathVariable Long
return ResponseEntity.status(500).body(Boolean.FALSE);
}

@PostMapping(EducGradBatchGraduationApiConstants.EXECUTE_REGEN_SCHOOL_REPORTS_BY_REQUEST)
/*@PostMapping(EducGradBatchGraduationApiConstants.EXECUTE_REGEN_SCHOOL_REPORTS_BY_REQUEST)
@PreAuthorize(PermissionsConstants.RUN_GRAD_ALGORITHM)
@Operation(summary = "Re-Generate School Reports for the given batchJobId", description = "Re-Generate School Reports for the given batchJobId", tags = { "RE-RUN" })
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"),@ApiResponse(responseCode = "500", description = "Internal Server Error")})
Expand All @@ -505,6 +497,36 @@ public ResponseEntity<String> launchRegenerateSchoolReports(@RequestBody Student
} catch (Exception e) {
return ResponseEntity.status(500).body(e.getLocalizedMessage());
}
}*/

@PostMapping(EducGradBatchGraduationApiConstants.EXECUTE_REGEN_SCHOOL_REPORTS_BY_REQUEST)
@PreAuthorize(PermissionsConstants.RUN_GRAD_ALGORITHM)
@Operation(summary = "Re-Generate School Reports for the given batchJobId", description = "Re-Generate School Reports for the given batchJobId", tags = { "RE-RUN" })
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"),@ApiResponse(responseCode = "500", description = "Internal Server Error")})
public ResponseEntity<BatchJobResponse> launchRegenerateSchoolReportsBatch(@RequestBody StudentSearchRequest searchRequest, @RequestParam(required = false) String type) {
logger.debug("launchSchoolReportRegenJob");
BatchJobResponse response = new BatchJobResponse();
JobParametersBuilder builder = new JobParametersBuilder();
builder.addLong(TIME, System.currentTimeMillis()).toJobParameters();
builder.addString(RUN_BY, ThreadLocalStateUtil.getCurrentUser());
builder.addString(JOB_TRIGGER, MANUAL);
builder.addString(JOB_TYPE, SCHL_RPT_REGEN);
response.setJobType(SCHL_RPT_REGEN);
response.setTriggerBy(MANUAL);
response.setStartTime(LocalDateTime.now());
response.setStatus(BatchStatusEnum.STARTED.name());

try {
String studentSearchData = jsonTransformer.marshall(searchRequest);
builder.addString(SEARCH_REQUEST, studentSearchData);
response.setJobParameters(studentSearchData);
JobExecution jobExecution = asyncJobLauncher.run(jobRegistry.getJob(REGENERATE_SCHOOL_REPORTS_BATCH_JOB), builder.toJobParameters());
response.setBatchId(jobExecution.getId());
return ResponseEntity.ok(response);
} catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException | JobParametersInvalidException | NoSuchJobException e) {
response.setException(e.getLocalizedMessage());
return ResponseEntity.status(500).body(response);
}
}

@PostMapping(EducGradBatchGraduationApiConstants.EXECUTE_REGEN_STUDENT_REPORTS_BY_REQUEST)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package ca.bc.gov.educ.api.batchgraduation.listener;

import ca.bc.gov.educ.api.batchgraduation.model.DistributionSummaryDTO;
import ca.bc.gov.educ.api.batchgraduation.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.stereotype.Component;

import java.util.Date;

import static ca.bc.gov.educ.api.batchgraduation.util.EducGradBatchGraduationApiConstants.SEARCH_REQUEST;

@Slf4j
@Component
public class RegenSchoolReportsCompletionNotificationListener extends BaseDistributionRunCompletionNotificationListener {

@Override
public void afterJob(JobExecution jobExecution) {
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
long elapsedTimeMillis = getElapsedTimeMillis(jobExecution);
log.info("=======================================================================================");
JobParameters jobParameters = jobExecution.getJobParameters();
ExecutionContext jobContext = jobExecution.getExecutionContext();
Long jobExecutionId = jobExecution.getId();
String jobType = jobParameters.getString("jobType");
log.info("{} Regen School Reports Job {} completed in {} s with jobExecution status {}", jobType, jobExecutionId, elapsedTimeMillis / 1000, jobExecution.getStatus());

String status = jobExecution.getStatus().toString();
Date startTime = DateUtils.toDate(jobExecution.getStartTime());
Date endTime = DateUtils.toDate(jobExecution.getEndTime());
String jobTrigger = jobParameters.getString("jobTrigger");

DistributionSummaryDTO summaryDTO = (DistributionSummaryDTO)jobContext.get("distributionSummaryDTO");

String studentSearchRequest = jobParameters.getString(SEARCH_REQUEST, "{}");
// display Summary Details
log.info("Records read : {}", summaryDTO.getReadCount());
log.info("Processed count: {}", summaryDTO.getProcessedCount());
log.info(" --------------------------------------------------------------------------------------");
log.info("Errors:{}", summaryDTO.getErrors().size());

updateUserSchedulingJobs(jobParameters);

String jobParametersDTO = buildJobParametersDTO(jobType, studentSearchRequest, null, null);
// save batch job & error history
processBatchJobHistory(summaryDTO, jobExecutionId, status, jobTrigger, jobType, startTime, endTime, jobParametersDTO);
log.info(" --------------------------------------------------------------------------------------");
summaryDTO.getSchools().forEach((value) -> log.info("School {} number of Regen School Reports : {}", value.getMincode(), value.getNumberOfSchoolReports()));

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ public enum JobProperName {
RCBJ ("Regenerate Certificates Batch Job"),
DSRBJ ("Delete Student Report Batch Job"),
ASBJ("Archive Students Batch Job"),
ASRBJ("Archive School Reports Batch Job");
ASRBJ("Archive School Reports Batch Job"),
SRRBJ("User Request School Report Regeneration")
;

private final String value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ public enum JobSelection {
RCBJ ("CERT_REGEN"),
DSRBJ ("TVR_DELETE"),
ASBJ("ARC_STUDENTS"),
ASRBJ("ARC_SCH_REPORTS");
ASRBJ("ARC_SCH_REPORTS"),
SRRBJ("SCHL_RPT_REGEN");

private final String value;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ca.bc.gov.educ.api.batchgraduation.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

@Data
@Component
@NoArgsConstructor
@AllArgsConstructor
public class SchoolReportsRegenerationRequest extends StudentSearchRequest {
private String runMode; // "Y" or "N"

public boolean runForAll () {
return (getSchoolOfRecords() == null || getSchoolOfRecords().isEmpty()) &&
(getSchoolCategoryCodes() == null || getSchoolCategoryCodes().isEmpty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ public enum TaskSelection {
RCBJ ("certRegenBatchJob"),
DSRBJ ("deleteStudentReportsBatchJob"),
ASBJ("archiveStudentsBatchJob"),
ASRBJ("archiveSchoolReportsBatchJob");
ASRBJ("archiveSchoolReportsBatchJob"),
SRRBJ("schoolReportsRegenBatchJob");

private final String value;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ca.bc.gov.educ.api.batchgraduation.processor;

import ca.bc.gov.educ.api.batchgraduation.model.*;
import ca.bc.gov.educ.api.batchgraduation.rest.RestUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
public class RegenerateSchoolReportsProcessor implements ItemProcessor<List<String>, List<String>> {

@Autowired
RestUtils restUtils;

@Value("#{stepExecutionContext['summary']}")
DistributionSummaryDTO summaryDTO;

@Override
public List<String> process(List<String> minCodes) throws Exception {
Long batchId = summaryDTO.getBatchId();
StudentSearchRequest searchRequest = summaryDTO.getStudentSearchRequest();
long countRegeneratedSchoolReports = 0l;
List<String> reportTypes = searchRequest.getReportTypes();
if(log.isDebugEnabled()) {
log.debug("Process Schools: {}", !minCodes.isEmpty() ? String.join(",", minCodes) : summaryDTO.getSchools().stream().map(School::getMincode).collect(Collectors.joining(",")));
}

String reportType;
if(reportTypes != null && !reportTypes.isEmpty() && "NONGRADPRJ".compareToIgnoreCase(reportTypes.get(0)) == 0)
reportType = "TVRRUN";
else
reportType = "GRADREG and NONGRADREG";

for (String mincode : minCodes) {
countRegeneratedSchoolReports += restUtils.createAndStoreSchoolReports(batchId, minCodes, reportType, summaryDTO);
}

summaryDTO.setProcessedCount(countRegeneratedSchoolReports);
return minCodes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package ca.bc.gov.educ.api.batchgraduation.reader;

import ca.bc.gov.educ.api.batchgraduation.model.*;
import ca.bc.gov.educ.api.batchgraduation.util.GradSchoolOfRecordFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.*;

import static ca.bc.gov.educ.api.batchgraduation.util.EducGradBatchGraduationApiConstants.SEARCH_REQUEST;

@Slf4j
public class RegenerateSchoolReportsPartitioner extends BasePartitioner {

@Value("#{stepExecution.jobExecution}")
JobExecution jobExecution;

@Autowired
GradSchoolOfRecordFilter gradSchoolOfRecordFilter;

public RegenerateSchoolReportsPartitioner() {
super();
}

@Override
public JobExecution getJobExecution() {
return jobExecution;
}

@Override
public Map<String, ExecutionContext> partition(int gridSize) {
DistributionSummaryDTO summaryDTO = (DistributionSummaryDTO)jobExecution.getExecutionContext().get("distributionSummaryDTO");
if(summaryDTO == null) {
summaryDTO = new DistributionSummaryDTO();
jobExecution.getExecutionContext().put("distributionSummaryDTO", summaryDTO);
}

StudentSearchRequest searchRequest = getStudentSearchRequest();
long startTime = System.currentTimeMillis();
log.debug("Filter Schools for school reports regeneration");
boolean processAllStudents = "ALL".equalsIgnoreCase(searchRequest.getActivityCode());
List<String> eligibleStudentSchoolDistricts = gradSchoolOfRecordFilter.filterSchoolOfRecords(searchRequest);
List<String> finalSchoolDistricts = eligibleStudentSchoolDistricts.stream().sorted().toList();
if(log.isDebugEnabled()) {
log.debug("Final list of eligible District / School codes {}", String.join(", ", finalSchoolDistricts));
}

summaryDTO.setBatchId(jobExecution.getId());
summaryDTO.setStudentSearchRequest(searchRequest);

long endTime = System.currentTimeMillis();
long diff = (endTime - startTime)/1000;
log.debug("Total {} schools after filters in {} sec", finalSchoolDistricts.size(), diff);

updateBatchJobHistory(createBatchJobHistory(), (long)finalSchoolDistricts.size());
summaryDTO.setReadCount((long)finalSchoolDistricts.size());
summaryDTO.setProcessedCount(0);

Map<String, ExecutionContext> map = new HashMap<>();
ExecutionContext executionContext = new ExecutionContext();
executionContext.put(SEARCH_REQUEST, searchRequest);
executionContext.put("data", finalSchoolDistricts);
executionContext.put("summary", summaryDTO);
executionContext.put("readCount", 0);
map.put("partition0", executionContext);

log.info("Found {} in total running on 1 partitions", finalSchoolDistricts);
return map;
}
}
Loading

0 comments on commit e5e7552

Please sign in to comment.