report generation executor

This commit is contained in:
root
2025-09-26 10:52:51 +05:00
parent 3a92d1400f
commit 18a363f772
4 changed files with 112 additions and 7 deletions
@@ -0,0 +1,24 @@
package kz.konturai.parser.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "reportGenerationExecutor")
public Executor reportGenerationExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("ReportGeneration-");
executor.initialize();
return executor;
}
}
@@ -1,10 +1,11 @@
package kz.konturai.parser.controller;
import kz.konturai.parser.dto.ReportGenerateRequest;
import kz.konturai.parser.dto.ReportGenerationResponse;
import kz.konturai.parser.dto.ApiResponse;
import kz.konturai.parser.model.ReportHistory;
import kz.konturai.parser.repository.ReportHistoryRepository;
import kz.konturai.parser.service.ReportGenerationService;
import kz.konturai.parser.service.ReportGenerationService.ReportBinary;
import kz.konturai.parser.service.MinIOService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
@@ -17,6 +18,8 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
import java.time.LocalDateTime;
import java.util.UUID;
import kz.konturai.parser.dto.PageResponse;
@@ -37,12 +40,25 @@ public class ReportController {
}
@PostMapping("/generate")
public ResponseEntity<byte[]> generate(@Validated @RequestBody ReportGenerateRequest request) {
ReportBinary rb = reportGenerationService.simpleGenerate(request);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + rb.getFilename() + "\"")
.contentType(rb.getMediaType())
.body(rb.getBytes());
public ResponseEntity<ApiResponse<ReportGenerationResponse>> generate(
@Validated @RequestBody ReportGenerateRequest request) {
// Generate unique task ID
String taskId = UUID.randomUUID().toString();
// Start async report generation
reportGenerationService.generateAsync(request);
// Calculate estimated completion time (5-10 minutes for complex reports)
LocalDateTime estimatedCompletion = LocalDateTime.now().plusMinutes(8);
ReportGenerationResponse response = new ReportGenerationResponse(
taskId,
"Отчёт будет сгенерирован в фоновом режиме. Ожидаемое время завершения: "
+ estimatedCompletion.format(java.time.format.DateTimeFormatter.ofPattern("HH:mm")),
estimatedCompletion,
"PROCESSING");
return ResponseEntity.ok(ApiResponse.success("Отчёт поставлен в очередь на генерацию", response));
}
@GetMapping("/history")
@@ -0,0 +1,53 @@
package kz.konturai.parser.dto;
import java.time.LocalDateTime;
public class ReportGenerationResponse {
private String taskId;
private String message;
private LocalDateTime estimatedCompletionTime;
private String status;
public ReportGenerationResponse() {
}
public ReportGenerationResponse(String taskId, String message, LocalDateTime estimatedCompletionTime,
String status) {
this.taskId = taskId;
this.message = message;
this.estimatedCompletionTime = estimatedCompletionTime;
this.status = status;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public LocalDateTime getEstimatedCompletionTime() {
return estimatedCompletionTime;
}
public void setEstimatedCompletionTime(LocalDateTime estimatedCompletionTime) {
this.estimatedCompletionTime = estimatedCompletionTime;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
@@ -6,6 +6,7 @@ import kz.konturai.parser.repository.MarketItemRepository;
import kz.konturai.parser.model.ReportHistory;
import kz.konturai.parser.repository.ReportHistoryRepository;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
@@ -130,6 +131,17 @@ public class ReportGenerationService {
generated.getBytes(java.nio.charset.StandardCharsets.UTF_8));
}
@Async("reportGenerationExecutor")
public void generateAsync(ReportGenerateRequest req) {
try {
generate(req);
// Report is automatically saved to database and MinIO in the generate() method
} catch (Exception e) {
// Log error but don't throw to avoid async method issues
System.err.println("Error generating report asynchronously: " + e.getMessage());
}
}
public ReportBinary generate(ReportGenerateRequest req) {
LocalDateTime start = req.getStartDate();
LocalDateTime end = req.getEndDate();