Skip to content

Commit

Permalink
Add "no preparation" mode and wait 15min before delete
Browse files Browse the repository at this point in the history
  • Loading branch information
valentin-boehm committed Nov 11, 2023
1 parent bba6c27 commit 0cc0a28
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 71 deletions.
120 changes: 64 additions & 56 deletions src/main/java/de/tum/cit/ase/service/SimulationService.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,69 +46,76 @@ public synchronized void simulateExam(
long courseId,
long examId,
ArtemisServer server,
boolean noPreparation,
ArtemisAccountDTO artemisAccountDTO
) {
boolean cleanupNeeded = false;
ArtemisAdmin admin;
ArtemisAdmin admin = null;

logAndSendInfo("Starting simulation with %d users on %s...", numberOfUsers, server.name());

try {
logAndSendInfo("Initializing admin...");
admin = server == ArtemisServer.PRODUCTION ? initializeAdminWithAccount(server, artemisAccountDTO) : initializeAdmin(server);
} catch (Exception e) {
logAndSendError("Error while initializing admin: %s", e.getMessage());
simulationWebsocketService.sendSimulationFailed();
return;
}

if (courseId == 0L && examId == 0L) {
logAndSendInfo("No course and exam specified. Creating course and exam...");
cleanupNeeded = true;
Course course;

// Create course
if (!noPreparation) {
try {
course = admin.createCourse();
logAndSendInfo("Initializing admin...");
admin =
server == ArtemisServer.PRODUCTION ? initializeAdminWithAccount(server, artemisAccountDTO) : initializeAdmin(server);
} catch (Exception e) {
logAndSendError("Error while creating course: %s", e.getMessage());
logAndSendError("Error while initializing admin: %s", e.getMessage());
simulationWebsocketService.sendSimulationFailed();
return;
}
logAndSendInfo("Successfully created course. Course ID: %d", course.getId());
// Create exam

if (courseId == 0L && examId == 0L) {
logAndSendInfo("No course and exam specified. Creating course and exam...");
cleanupNeeded = true;
Course course;

// Create course
try {
course = admin.createCourse();
} catch (Exception e) {
logAndSendError("Error while creating course: %s", e.getMessage());
simulationWebsocketService.sendSimulationFailed();
return;
}
logAndSendInfo("Successfully created course. Course ID: %d", course.getId());
// Create exam
try {
var exam = createAndInitializeExam(numberOfUsers, server, admin, course);
courseId = exam.getCourse().getId();
examId = exam.getId();
} catch (Exception e) {
logAndSendError("Error while creating exam: %s", e.getMessage());
ArtemisAdmin finalAdmin = admin;
new Thread(() -> cleanup(finalAdmin, course.getId())).start();
simulationWebsocketService.sendSimulationFailed();
return;
}
logAndSendInfo("Successfully initialized exam. Exam ID: %d", examId);
} else {
logAndSendInfo("Using existing course %d and exam %d.", courseId, examId);
}
try {
var exam = createAndInitializeExam(numberOfUsers, server, admin, course);
courseId = exam.getCourse().getId();
examId = exam.getId();
logAndSendInfo("Preparing exam for simulation...");
admin.prepareExam(courseId, examId);
} catch (Exception e) {
logAndSendError("Error while creating exam: %s", e.getMessage());
cleanup(admin, course.getId());
logAndSendError("Error while preparing exam: %s", e.getMessage());
if (cleanupNeeded) {
ArtemisAdmin finalAdmin1 = admin;
long finalCourseId1 = courseId;
new Thread(() -> cleanup(finalAdmin1, finalCourseId1)).start();
}
simulationWebsocketService.sendSimulationFailed();
return;
}
logAndSendInfo("Successfully initialized exam. Exam ID: %d", examId);
} else {
logAndSendInfo("Using existing course %d and exam %d.", courseId, examId);
}
try {
logAndSendInfo("Preparing exam for simulation...");
admin.prepareExam(courseId, examId);
} catch (Exception e) {
logAndSendError("Error while preparing exam: %s", e.getMessage());
if (cleanupNeeded) {
cleanup(admin, courseId);
}
simulationWebsocketService.sendSimulationFailed();
return;
}

logAndSendInfo("Preparation finished...");
try {
// Wait for a couple of seconds. Without this, students cannot access their repos.
// Not sure why this is necessary, trying to figure it out
sleep(5_000);
} catch (InterruptedException ignored) {}
logAndSendInfo("Preparation finished...");
try {
// Wait for a couple of seconds. Without this, students cannot access their repos.
// Not sure why this is necessary, trying to figure it out
sleep(5_000);
} catch (InterruptedException ignored) {}
}

logAndSendInfo("Starting simulation...");

Expand Down Expand Up @@ -143,7 +150,9 @@ public synchronized void simulateExam(
} catch (Exception e) {
logAndSendError("Error while performing simulation: %s", e.getMessage());
if (cleanupNeeded) {
cleanup(admin, courseId);
ArtemisAdmin finalAdmin2 = admin;
long finalCourseId2 = courseId;
new Thread(() -> cleanup(finalAdmin2, finalCourseId2)).start();
}
simulationWebsocketService.sendSimulationFailed();
return;
Expand All @@ -156,7 +165,9 @@ public synchronized void simulateExam(
simulationWebsocketService.sendSimulationResult(simulationResult);
if (cleanupNeeded) {
simulationWebsocketService.sendSimulationError("The result is available, but please note that the cleanup is still running!");
cleanup(admin, courseId);
ArtemisAdmin finalAdmin3 = admin;
long finalCourseId3 = courseId;
new Thread(() -> cleanup(finalAdmin3, finalCourseId3)).start();
}
simulationWebsocketService.sendSimulationCompleted();
}
Expand All @@ -182,7 +193,7 @@ private Exam createAndInitializeExam(int numberOfUsers, ArtemisServer server, Ar

logAndSendInfo("Successfully created course and exam. Waiting for synchronization of user groups (1 min)...");
try {
sleep(1000 * 60); //Wait for 1 minutes until user groups are synchronized
sleep(1000 * 60); //Wait for 1 minute until user groups are synchronized
} catch (InterruptedException ignored) {}

// Create exam exercises and register students
Expand Down Expand Up @@ -233,16 +244,13 @@ private List<RequestStat> performActionWithAll(int threadCount, int numberOfUser
}

private void cleanup(ArtemisAdmin admin, long courseId) {
logAndSendInfo("Cleaning up... Depending on the number of users, this may take a few minutes.");
logAndSendInfo("Cleaning up... Note that the cleanup will happen in 15min.");
try {
sleep(1000 * 10); // Give the server a few seconds to recover
sleep(1000 * 60 * 15); // Wait 15min for builds to finish before deleting the course
admin.deleteCourse(courseId);
logAndSendInfo("Successfully cleaned up.");
logAndSendInfo("Successfully cleaned up course %d.", courseId);
} catch (Exception e) {
logAndSendError("Error while cleaning up: %s", e.getMessage());
logAndSendError(
"The deletion of the course failed, potentially due to overloading of the Artemis Server. Please wait a few minutes and then delete the course 'Temporary Benchmarking Exam' manually. If the course is already deleted, make sure that the project 'benchmark Programming Exercise for Benchmarking' is deleted from the VCS as well."
);
logAndSendError("Error while cleaning up course %d: %s", courseId, e.getMessage());
}
}

Expand Down
10 changes: 7 additions & 3 deletions src/main/java/de/tum/cit/ase/web/rest/SimulationResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public ResponseEntity<Void> startSimulation(
@RequestParam(value = "courseId") int courseId,
@RequestParam(value = "examId") int examId,
@RequestParam(value = "server") ArtemisServer server,
@RequestParam(value = "noPreparation") boolean noPreparation,
@RequestBody(required = false) ArtemisAccountDTO artemisAccountDTO
) {
if (numberOfUsers <= 0 || courseId < 0 || examId < 0 || server == null) {
Expand All @@ -35,11 +36,14 @@ public ResponseEntity<Void> startSimulation(
if ((courseId == 0) ^ (examId == 0)) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
// Production only with admin account
if (server == ArtemisServer.PRODUCTION && artemisAccountDTO == null) {
// Production with preparation only with admin account
if (server == ArtemisServer.PRODUCTION && artemisAccountDTO == null && !noPreparation) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
simulationService.simulateExam(numberOfUsers, courseId, examId, server, artemisAccountDTO);
if (courseId == 0 && noPreparation) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
simulationService.simulateExam(numberOfUsers, courseId, examId, server, noPreparation, artemisAccountDTO);
return new ResponseEntity<>(HttpStatus.OK);
}
}
23 changes: 16 additions & 7 deletions src/main/webapp/app/simulations/simulations.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
</div>
<div class="input-wrapper">
<label for="useExisitingExam">Use existing exam</label>
<input id="useExisitingExam" type="checkbox" [(ngModel)]="useExistingExam" />
<input id="useExisitingExam" type="checkbox" [(ngModel)]="useExistingExam" (change)="useExistingExamChanged()" />
</div>
<div class="input-wrapper" *ngIf="useExistingExam">
<label for="noPreparation">No preparation</label>
<input id="noPreparation" type="checkbox" [(ngModel)]="noPreparation" />
</div>
<div class="input-wrapper" *ngIf="useExistingExam">
<label for="course">Course ID</label>
Expand All @@ -24,11 +28,11 @@
<label for="exam">Exam ID</label>
<input id="exam" type="number" min="0" [(ngModel)]="examId" />
</div>
<div class="input-wrapper" *ngIf="selectedServer == ArtemisServer.PRODUCTION">
<div class="input-wrapper" *ngIf="selectedServer == ArtemisServer.PRODUCTION && !noPreparation">
<label for="adminUsername">Admin Username</label>
<input id="adminUsername" type="text" [(ngModel)]="adminUsername" />
</div>
<div class="input-wrapper" *ngIf="selectedServer == ArtemisServer.PRODUCTION">
<div class="input-wrapper" *ngIf="selectedServer == ArtemisServer.PRODUCTION && !noPreparation">
<label for="adminPassword">Admin Password</label>
<input id="adminPassword" type="password" [(ngModel)]="adminPassword" />
</div>
Expand Down Expand Up @@ -63,9 +67,9 @@
<p>
The Benchmarking Tool will use an existing exam for the simulation. Please specify the IDs of course and exam and make sure that the
necessary number of test-users (1 - {{ numberOfUsers }}) are registered for the exam.
<span class="warning">Please be aware that:</span>
<span class="warning" *ngIf="!noPreparation">Please be aware that:</span>
</p>
<ul>
<ul *ngIf="!noPreparation">
<li>The start- and end-date of the exam will be changed. The change will NOT be undone after the simulation!</li>
<li>
The student exams will be (re-)generated and prepared. This affects the exams of ALL registered students, not just the test-users!
Expand All @@ -76,15 +80,20 @@
<span class="warning">Make sure that no real students are registered!</span>
</li>
</ul>
<p *ngIf="noPreparation">
The Benchmarking Tool will not make any changes in the course and exam. Please make sure that the exam is fully prepared.
</p>
<ng-container *ngIf="selectedServer == ArtemisServer.PRODUCTION">
<p>
The Benchmarking Tool will simulate on the <span class="warning">Artemis Production Instance</span>! (<a
target="_blank"
href="https://artemis.cit.tum.de"
>https://artemis.cit.tum.de</a
>)<br />
Since the tool does not have admin access on Production, you need to provide admin credentials. They will only be used for this one
simulation and not be stored.
<span *ngIf="!noPreparation"
>Since the tool does not have admin access on Production, you need to provide admin credentials. They will only be used for this
one simulation and not be stored.</span
>
</p>
<p>
Please note that performing a simulation with a large number of users can have a negative impact on the performance of the
Expand Down
17 changes: 13 additions & 4 deletions src/main/webapp/app/simulations/simulations.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class SimulationsComponent implements OnInit {
adminPassword = '';
adminUsername = '';
availableServers = [ArtemisServer.TS1, ArtemisServer.TS3, ArtemisServer.PRODUCTION, ArtemisServer.STAGING];
noPreparation = false;

protected readonly ArtemisServer = ArtemisServer;

Expand Down Expand Up @@ -64,6 +65,7 @@ export class SimulationsComponent implements OnInit {
if (!this.useExistingExam) {
this.courseId = 0;
this.examId = 0;
this.noPreparation = false;
}
this.logMessages = [];
const observer = {
Expand All @@ -76,11 +78,11 @@ export class SimulationsComponent implements OnInit {
};

let account;
if (this.selectedServer === ArtemisServer.PRODUCTION) {
if (this.selectedServer === ArtemisServer.PRODUCTION && !this.noPreparation) {
account = new ArtemisAccountDTO(this.adminUsername, this.adminPassword);
}
this.simulationsService
.startSimulation(this.numberOfUsers, this.courseId, this.examId, this.selectedServer, account)
.startSimulation(this.numberOfUsers, this.courseId, this.examId, this.selectedServer, this.noPreparation, account)
.subscribe(observer);
}

Expand All @@ -89,10 +91,17 @@ export class SimulationsComponent implements OnInit {
return (
this.numberOfUsers > 0 &&
(!this.useExistingExam || (this.courseId > 0 && this.examId > 0)) &&
this.adminPassword.length > 0 &&
this.adminUsername.length > 0
((this.adminPassword.length > 0 && this.adminUsername.length > 0) || this.noPreparation)
);
}
return this.numberOfUsers > 0 && (!this.useExistingExam || (this.courseId > 0 && this.examId > 0));
}

useExistingExamChanged(): void {
if (!this.useExistingExam) {
this.courseId = 0;
this.examId = 0;
this.noPreparation = false;
}
}
}
12 changes: 11 additions & 1 deletion src/main/webapp/app/simulations/simulations.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,20 @@ export class SimulationsService {
courseId: number,
examId: number,
server: ArtemisServer,
noPreparation: boolean,
account?: ArtemisAccountDTO,
): Observable<object> {
const endpoint = this.applicationConfigService.getEndpointFor(
'/api/simulations?users=' + numberOfUsers + '&courseId=' + courseId + '&examId=' + examId + '&server=' + server,
'/api/simulations?users=' +
numberOfUsers +
'&courseId=' +
courseId +
'&examId=' +
examId +
'&server=' +
server +
'&noPreparation=' +
noPreparation,
);
if (!window.location.protocol.startsWith('https:')) {
// Only send credentials over HTTPS
Expand Down

0 comments on commit 0cc0a28

Please sign in to comment.