Added submissions.csv to sample data, and improved concurrency.

This commit is contained in:
Andrew Lalis 2023-01-26 14:07:41 +01:00
parent 3908c2becd
commit d1aa06dd95
7 changed files with 65 additions and 27 deletions

View File

@ -45,7 +45,8 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<!-- TODO: Change this to "test" once the SampleDataLoader is refactored to the tests. -->
<scope>compile</scope>
</dependency>
</dependencies>

View File

@ -1,2 +1,4 @@
nl,groningen,Groningen
nl,amsterdam,Amsterdam
us,tampa,Tampa
us,new-york-city,New York City
1 nl groningen Groningen
2 nl amsterdam Amsterdam
3 us tampa Tampa
4 us new-york-city New York City

View File

@ -0,0 +1,2 @@
barbell-overhead-press,60,KG,1,Andrew Lalis,nl_groningen_trainmore-munnekeholm,sample_video_ohp.mp4
incline-dumbbell-bicep-curl,14,KG,10,Andrew Lalis,nl_groningen_trainmore-munnekeholm,sample_video_curl.mp4
1 barbell-overhead-press 60 KG 1 Andrew Lalis nl_groningen_trainmore-munnekeholm sample_video_ohp.mp4
2 incline-dumbbell-bicep-curl 14 KG 10 Andrew Lalis nl_groningen_trainmore-munnekeholm sample_video_curl.mp4

View File

@ -1,25 +1,11 @@
package nl.andrewlalis.gymboard_api.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfig {
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("gymboard-api-");
executor.initialize();
return executor;
}
}

View File

@ -1,18 +1,25 @@
package nl.andrewlalis.gymboard_api.model;
import nl.andrewlalis.gymboard_api.controller.dto.CompoundGymId;
import nl.andrewlalis.gymboard_api.controller.dto.ExerciseSubmissionPayload;
import nl.andrewlalis.gymboard_api.dao.CityRepository;
import nl.andrewlalis.gymboard_api.dao.CountryRepository;
import nl.andrewlalis.gymboard_api.dao.GymRepository;
import nl.andrewlalis.gymboard_api.dao.exercise.ExerciseRepository;
import nl.andrewlalis.gymboard_api.model.exercise.Exercise;
import nl.andrewlalis.gymboard_api.model.exercise.ExerciseSubmission;
import nl.andrewlalis.gymboard_api.service.ExerciseSubmissionService;
import nl.andrewlalis.gymboard_api.service.UploadService;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.FileReader;
import java.io.IOException;
@ -31,17 +38,21 @@ public class SampleDataLoader implements ApplicationListener<ContextRefreshedEve
private final CityRepository cityRepository;
private final GymRepository gymRepository;
private final ExerciseRepository exerciseRepository;
private final ExerciseSubmissionService submissionService;
private final UploadService uploadService;
public SampleDataLoader(
CountryRepository countryRepository,
CityRepository cityRepository,
GymRepository gymRepository,
ExerciseRepository exerciseRepository
) {
CountryRepository countryRepository,
CityRepository cityRepository,
GymRepository gymRepository,
ExerciseRepository exerciseRepository,
ExerciseSubmissionService submissionService, UploadService uploadService) {
this.countryRepository = countryRepository;
this.cityRepository = cityRepository;
this.gymRepository = gymRepository;
this.exerciseRepository = exerciseRepository;
this.submissionService = submissionService;
this.uploadService = uploadService;
}
@Override
@ -84,10 +95,40 @@ public class SampleDataLoader implements ApplicationListener<ContextRefreshedEve
record.get(7)
));
});
loadCsv("submissions", record -> {
var exercise = exerciseRepository.findById(record.get(0)).orElseThrow();
BigDecimal weight = new BigDecimal(record.get(1));
ExerciseSubmission.WeightUnit unit = ExerciseSubmission.WeightUnit.valueOf(record.get(2).toUpperCase());
int reps = Integer.parseInt(record.get(3));
String name = record.get(4);
CompoundGymId gymId = CompoundGymId.parse(record.get(5));
String videoFilename = record.get(6);
try {
var uploadResp = uploadService.handleSubmissionUpload(gymId, new MockMultipartFile(
videoFilename,
videoFilename,
"video/mp4",
Files.readAllBytes(Path.of("sample_data", videoFilename))
));
submissionService.createSubmission(gymId, new ExerciseSubmissionPayload(
name,
exercise.getShortName(),
weight.floatValue(),
unit.name(),
reps,
uploadResp.id()
));
} catch (IOException e) {
e.printStackTrace();
}
});
}
private void loadCsv(String csvName, Consumer<CSVRecord> recordConsumer) throws IOException {
var reader = new FileReader("sample_data/" + csvName + ".csv");
String path = "sample_data/" + csvName + ".csv";
log.info("Loading data from {}...", path);
var reader = new FileReader(path);
for (var record : CSVFormat.DEFAULT.parse(reader)) {
recordConsumer.accept(record);
}

View File

@ -18,7 +18,6 @@ import nl.andrewlalis.gymboard_api.model.exercise.ExerciseSubmissionVideoFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -33,6 +32,7 @@ import java.time.Instant;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
/**
@ -49,19 +49,23 @@ public class ExerciseSubmissionService {
private final ExerciseSubmissionRepository exerciseSubmissionRepository;
private final ExerciseSubmissionTempFileRepository tempFileRepository;
private final ExerciseSubmissionVideoFileRepository submissionVideoFileRepository;
private final Executor taskExecutor;
public ExerciseSubmissionService(GymRepository gymRepository,
StoredFileRepository fileRepository,
ExerciseRepository exerciseRepository,
ExerciseSubmissionRepository exerciseSubmissionRepository,
ExerciseSubmissionTempFileRepository tempFileRepository,
ExerciseSubmissionVideoFileRepository submissionVideoFileRepository) {
ExerciseSubmissionVideoFileRepository submissionVideoFileRepository,
Executor taskExecutor
) {
this.gymRepository = gymRepository;
this.fileRepository = fileRepository;
this.exerciseRepository = exerciseRepository;
this.exerciseSubmissionRepository = exerciseSubmissionRepository;
this.tempFileRepository = tempFileRepository;
this.submissionVideoFileRepository = submissionVideoFileRepository;
this.taskExecutor = taskExecutor;
}
@Transactional(readOnly = true)
@ -132,7 +136,7 @@ public class ExerciseSubmissionService {
public void processWaitingSubmissions() {
List<ExerciseSubmission> waitingSubmissions = exerciseSubmissionRepository.findAllByStatus(ExerciseSubmission.Status.WAITING);
for (var submission : waitingSubmissions) {
processSubmission(submission.getId());
taskExecutor.execute(() -> processSubmission(submission.getId()));
}
}
@ -146,8 +150,7 @@ public class ExerciseSubmissionService {
* </p>
* @param submissionId The submission's id.
*/
@Async
public void processSubmission(long submissionId) {
private void processSubmission(long submissionId) {
log.info("Starting processing of submission {}.", submissionId);
// First try and fetch the submission.
Optional<ExerciseSubmission> optionalSubmission = exerciseSubmissionRepository.findById(submissionId);

View File

@ -5,3 +5,6 @@ spring.datasource.url=jdbc:postgresql://localhost:5432/gymboard-api-dev
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=false
spring.task.execution.pool.core-size=3
spring.task.execution.pool.max-size=10