[Updated] Dockerfiles so everything runs using docker compose up, added the benchmark and speed tests
This commit is contained in:
+13
-2
@@ -16,11 +16,22 @@ ENV USER=dev
|
|||||||
RUN groupadd -g ${GID} ${USER} \
|
RUN groupadd -g ${GID} ${USER} \
|
||||||
&& useradd -m -u ${UID} -g ${USER} ${USER}
|
&& useradd -m -u ${UID} -g ${USER} ${USER}
|
||||||
USER ${USER}
|
USER ${USER}
|
||||||
EXPOSE 8080
|
EXPOSE 9090
|
||||||
CMD ["tail","-f","/dev/null"]
|
CMD ["tail","-f","/dev/null"]
|
||||||
|
|
||||||
#---Building
|
#---Building
|
||||||
|
FROM base AS build
|
||||||
|
COPY . .
|
||||||
|
RUN mvn clean package -DskipTests
|
||||||
|
|
||||||
|
#--Testing
|
||||||
|
FROM build AS testing
|
||||||
|
RUN mvn clean test
|
||||||
|
|
||||||
#---Production
|
#---Production
|
||||||
|
# Pulled again to get rid of maven, to decrease the size
|
||||||
|
FROM openjdk:17-jdk-slim AS production
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=build /app/target/*.jar app.jar
|
||||||
|
EXPOSE 9090
|
||||||
|
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||||
@@ -23,28 +23,46 @@ public class QuizController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private QuizService quizService;
|
private QuizService quizService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a session
|
||||||
|
* @param amount The amount of questsions
|
||||||
|
* @param category The desired category (or all)
|
||||||
|
* @param difficulty The desired difficulty (or all)
|
||||||
|
* @param type The desired type (or both)
|
||||||
|
* @return The sessionId, or statusCode 5 when the queue is full
|
||||||
|
*/
|
||||||
@GetMapping("/questions")
|
@GetMapping("/questions")
|
||||||
public String startSession(
|
public String startSession(
|
||||||
@RequestParam(required = true) Integer amount,
|
@RequestParam(required = true) Integer amount,
|
||||||
@RequestParam(required = false) Integer category,
|
@RequestParam(required = false) Integer category,
|
||||||
@RequestParam(required = false) String difficulty,
|
@RequestParam(required = false) String difficulty,
|
||||||
@RequestParam(required = false) String type
|
@RequestParam(required = false) String type
|
||||||
) {
|
) {
|
||||||
QuizSettings quizSettings = new QuizSettings(amount, category, difficulty, type);
|
QuizSettings quizSettings = new QuizSettings(amount, category, difficulty, type);
|
||||||
Optional<String> result = quizService.createSession(quizSettings);
|
Optional<String> result = quizService.createSession(quizSettings);
|
||||||
if(result.isPresent()) {
|
if (result.isPresent()) {
|
||||||
String jsonString = String.format("{\"statusCode\":0,\"sessionId\":\"%s\"}", result.get());
|
String jsonString = String.format("{\"statusCode\":0,\"sessionId\":\"%s\"}", result.get());
|
||||||
return jsonString;
|
return jsonString;
|
||||||
}
|
}
|
||||||
String jsonString = String.format("{\"statusCode\":5}");
|
String jsonString = String.format("{\"statusCode\":5}");
|
||||||
return jsonString;
|
return jsonString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the questions have been retrieved
|
||||||
|
* @param sessionId The session that holds the questions
|
||||||
|
* @return The Session, or nothing if they are not ready yet
|
||||||
|
*/
|
||||||
@GetMapping("/status/{sessionId}")
|
@GetMapping("/status/{sessionId}")
|
||||||
public Optional<Session> checkStatus(@PathVariable String sessionId) {
|
public Optional<Session> checkStatus(@PathVariable String sessionId) {
|
||||||
return quizService.checkSession(sessionId);
|
return quizService.checkSession(sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive the chosen answers, calculate the score, and return it
|
||||||
|
* @param answers The chosen answers
|
||||||
|
* @return The score
|
||||||
|
*/
|
||||||
@PostMapping("/score")
|
@PostMapping("/score")
|
||||||
public String checkAnswers(@RequestBody Answers answers) {
|
public String checkAnswers(@RequestBody Answers answers) {
|
||||||
String jsonString = String.format("{\"score\":\"%s\"}", quizService.getScore(answers));
|
String jsonString = String.format("{\"score\":\"%s\"}", quizService.getScore(answers));
|
||||||
|
|||||||
@@ -48,4 +48,21 @@ public class ApiService {
|
|||||||
logger.log(System.Logger.Level.ERROR, "Critical failure", e);
|
logger.log(System.Logger.Level.ERROR, "Critical failure", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect a chuck of 50 items
|
||||||
|
* Store them in the DataService
|
||||||
|
*/
|
||||||
|
public void collectBulk() {
|
||||||
|
String url = apiUrl + "?amount=50";
|
||||||
|
try {
|
||||||
|
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
|
||||||
|
String json = response.getBody();
|
||||||
|
ApiResponse apiResponse = cleanerService.extractApiResponse(json);
|
||||||
|
responseHandler.handleResponse(apiResponse);
|
||||||
|
|
||||||
|
} catch (RestClientException | IOException e) {
|
||||||
|
logger.log(System.Logger.Level.ERROR, "Critical failure", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class ResponseHandlingService {
|
|||||||
|
|
||||||
switch (response.getResponseCode()) {
|
switch (response.getResponseCode()) {
|
||||||
case 0:
|
case 0:
|
||||||
// Nothing
|
// Success
|
||||||
updateSessionInCache(session, response);
|
updateSessionInCache(session, response);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@@ -58,7 +58,7 @@ public class ResponseHandlingService {
|
|||||||
/**
|
/**
|
||||||
* If the request was made by the scheduler during queue-downtime, there is no session
|
* If the request was made by the scheduler during queue-downtime, there is no session
|
||||||
*/
|
*/
|
||||||
public void switchInternal(ApiResponse response) {
|
public void handleResponse(ApiResponse response) {
|
||||||
switch (response.getResponseCode()) {
|
switch (response.getResponseCode()) {
|
||||||
case 0:
|
case 0:
|
||||||
// TODO: Store in DB
|
// TODO: Store in DB
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class ApiServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testRequestQuestions() throws Exception {
|
public void testRequestQuestions() throws Exception {
|
||||||
QuizSettings settings = new QuizSettings();
|
QuizSettings settings = new QuizSettings();
|
||||||
String jsonResponse = apiService.requestQuestions(settings);
|
String jsonResponse = apiService.handleRequest(settings);
|
||||||
JsonNode jsonNode = objectMapper.readTree(jsonResponse);
|
JsonNode jsonNode = objectMapper.readTree(jsonResponse);
|
||||||
|
|
||||||
// Check if the response code is as expected
|
// Check if the response code is as expected
|
||||||
|
|||||||
@@ -8,3 +8,12 @@ services:
|
|||||||
container_name: quiz-frontend-prod-cont
|
container_name: quiz-frontend-prod-cont
|
||||||
ports:
|
ports:
|
||||||
- "4200:80"
|
- "4200:80"
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ./backend
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: production
|
||||||
|
image: quiz-backend-prod
|
||||||
|
container_name: quiz-backend-prod-cont
|
||||||
|
ports:
|
||||||
|
- "9090:9090"
|
||||||
+1
-1
@@ -22,7 +22,7 @@ COPY package*.json ./
|
|||||||
RUN npm install
|
RUN npm install
|
||||||
# Copied here, since the the Development setup uses a bind volume instead
|
# Copied here, since the the Development setup uses a bind volume instead
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN npm run build --prod
|
RUN ng build --configuration production
|
||||||
|
|
||||||
#--- Production
|
#--- Production
|
||||||
FROM nginx:alpine AS production
|
FROM nginx:alpine AS production
|
||||||
|
|||||||
@@ -50,6 +50,12 @@
|
|||||||
"maximumError": "4kB"
|
"maximumError": "4kB"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
"outputHashing": "all"
|
"outputHashing": "all"
|
||||||
},
|
},
|
||||||
"development": {
|
"development": {
|
||||||
|
|||||||
@@ -18,12 +18,13 @@ import { Answers } from '../models/answers';
|
|||||||
import { StorageService } from './storage.service';
|
import { StorageService } from './storage.service';
|
||||||
import { CleanerService } from './cleaner.service';
|
import { CleanerService } from './cleaner.service';
|
||||||
import { ResponseHandlerService } from './response-handler.service';
|
import { ResponseHandlerService } from './response-handler.service';
|
||||||
|
import { environment } from '../../../environments/environment';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class QuizService {
|
export class QuizService {
|
||||||
private apiUrl = 'http://localhost:9090/quiz';
|
private apiUrl = environment.apiUrl + '/quiz';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export const environment = {
|
||||||
|
production: true,
|
||||||
|
/** Connecting through the docker compose network is not working for now, so I'll have to use the localhost */
|
||||||
|
// apiUrl: 'http://backend:9090',
|
||||||
|
apiUrl: 'http://localhost:9090',
|
||||||
|
};
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export const environment = {
|
||||||
|
production: false,
|
||||||
|
apiUrl: 'http://localhost:9090'
|
||||||
|
};
|
||||||
Executable
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
start_time=$(date +%s)
|
||||||
|
|
||||||
|
for i in {1..6}; do
|
||||||
|
./LoadTestOne.sh &
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
|
||||||
|
wait # Wait for all background jobs to finish
|
||||||
|
|
||||||
|
end_time=$(date +%s) # Capture the end time
|
||||||
|
|
||||||
|
# Calculate and print the elapsed time
|
||||||
|
elapsed_time=$((end_time - start_time))
|
||||||
|
echo "Done!"
|
||||||
|
echo "Total time taken: $elapsed_time seconds"
|
||||||
Executable
+37
@@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Step 1: Get the sessionId from the questions endpoint
|
||||||
|
sessionIdJson=$(curl -s http://localhost:9090/quiz/questions?amount=5)
|
||||||
|
|
||||||
|
statusCode=$(echo "$sessionIdJson" | grep -o '"statusCode":[0-9]*' | sed 's/"statusCode"://')
|
||||||
|
|
||||||
|
if [ "$statusCode" -ne 0 ]; then
|
||||||
|
echo "Exiting: statusCode is not 0."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sessionId=$(echo "$sessionIdJson" | grep -o '"sessionId":"[^"]*"' | sed 's/"sessionId":"//;s/"//')
|
||||||
|
|
||||||
|
if [ -z "$sessionId" ]; then
|
||||||
|
echo "Failed to get sessionId"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Received sessionId: $sessionId"
|
||||||
|
|
||||||
|
# Step 2: Poll the status endpoint every 2 seconds
|
||||||
|
while true; do
|
||||||
|
status_response=$(curl -s http://localhost:9090/quiz/status/"$sessionId")
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
# Check if the response is JSON (starts with '{')
|
||||||
|
if [[ $status_response == \{* ]]; then
|
||||||
|
echo "$sessionId: done!"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Status check failed, retrying..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
Reference in New Issue
Block a user