Skip to content

Commit

Permalink
[#11252] Use different method to impose request timeout limit (#11259)
Browse files Browse the repository at this point in the history
  • Loading branch information
wkurniawan07 authored Jul 11, 2021
1 parent a7a37fb commit 6484257
Show file tree
Hide file tree
Showing 14 changed files with 113 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.google.cloud.datastore.DatastoreException;

import teammates.common.exception.DeadlineExceededException;
import teammates.common.exception.EntityNotFoundException;
import teammates.common.exception.InvalidHttpParameterException;
import teammates.common.exception.UnauthorizedAccessException;
Expand All @@ -29,6 +30,7 @@ protected void prepareBrowser() {
public void testAll() {
testAssertionError();
testNullPointerException();
testDeadlineExceededException();
testDatastoreException();
testUnauthorizedAccessException();
testInvalidHttpParameterException();
Expand Down Expand Up @@ -63,6 +65,20 @@ private void testNullPointerException() {

}

private void testDeadlineExceededException() {

______TS("DeadlineExceededException testing");

String url = createUrl(Const.ResourceURIs.EXCEPTION)
.withParam(Const.ParamsNames.ERROR, DeadlineExceededException.class.getSimpleName())
.toString();

BACKDOOR.executeGetRequest(url, null);

print("DeadlineExceededException triggered, verify that you have received error logs via email");

}

private void testDatastoreException() {

______TS("DatastoreException testing");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package teammates.common.exception;

/**
* Exception thrown when an operation is determined to have exceeded the time it is allowed to run.
*/
public class DeadlineExceededException extends RuntimeException {
}
17 changes: 15 additions & 2 deletions src/main/java/teammates/common/util/RequestTracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.time.Instant;
import java.time.temporal.ChronoUnit;

import teammates.common.exception.DeadlineExceededException;

/**
* Stores the information of the current HTTP request.
*/
Expand Down Expand Up @@ -39,14 +41,25 @@ public static String getSpanId() {
/**
* Returns the remaining time (in millis) until the current request times out.
*/
public static long getRemainingTimeMillis() {
private static long getRemainingTimeMillis() {
RequestTrace trace = THREAD_LOCAL.get();
if (trace == null) {
return -1L;
return 1L;
}
return trace.timeoutTimestamp - Instant.now().toEpochMilli();
}

/**
* Throws {@link DeadlineExceededException} if the current thread has exceeded
* the limit for serving request.
*/
public static void checkRemainingTime() {
long remainingTime = getRemainingTimeMillis();
if (remainingTime < 0) {
throw new DeadlineExceededException();
}
}

/**
* Returns the remaining time (in millis) until the current request times out.
*/
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/teammates/logic/api/EmailGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import teammates.common.util.EmailType;
import teammates.common.util.EmailWrapper;
import teammates.common.util.Logger;
import teammates.common.util.RequestTracer;
import teammates.common.util.SanitizationHelper;
import teammates.common.util.StringHelper;
import teammates.common.util.Templates;
Expand Down Expand Up @@ -275,6 +276,7 @@ private EmailWrapper generateSessionLinksRecoveryEmailForExistingStudent(String
List<FeedbackSessionAttributes> sessions = fsLogic.getAllFeedbackSessionsWithinTimeRange(startTime, endTime);

for (FeedbackSessionAttributes session : sessions) {
RequestTracer.checkRemainingTime();
String courseId = session.getCourseId();
CourseAttributes course = coursesLogic.getCourse(courseId);
List<StudentAttributes> students = studentsForEmail.stream().filter(
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/teammates/logic/core/FeedbackSessionsLogic.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import teammates.common.exception.InvalidParametersException;
import teammates.common.util.Const;
import teammates.common.util.Logger;
import teammates.common.util.RequestTracer;
import teammates.common.util.TimeHelper;
import teammates.storage.api.FeedbackSessionsDb;

Expand Down Expand Up @@ -532,6 +533,7 @@ public SessionResultsBundle getSessionResultsForUser(
for (FeedbackQuestionAttributes qn : allQuestions) {
allQuestionsMap.put(qn.getId(), qn);
}
RequestTracer.checkRemainingTime();

// load response(s)
StudentAttributes student = getStudent(courseId, userEmail, role);
Expand All @@ -556,6 +558,7 @@ public SessionResultsBundle getSessionResultsForUser(
allResponses.addAll(viewableResponses);
}
}
RequestTracer.checkRemainingTime();

// load comment(s)
List<FeedbackResponseCommentAttributes> allComments;
Expand All @@ -564,6 +567,7 @@ public SessionResultsBundle getSessionResultsForUser(
} else {
allComments = frcLogic.getFeedbackResponseCommentForQuestionInSection(questionId, section);
}
RequestTracer.checkRemainingTime();

// related questions, responses, and comment
Map<String, FeedbackQuestionAttributes> relatedQuestionsMap = new HashMap<>();
Expand Down Expand Up @@ -610,6 +614,7 @@ public SessionResultsBundle getSessionResultsForUser(
responseRecipientVisibilityTable.put(response.getId(),
frLogic.isNameVisibleToUser(correspondingQuestion, response, userEmail, role, false, roster));
}
RequestTracer.checkRemainingTime();

// build comment
for (FeedbackResponseCommentAttributes frc : allComments) {
Expand All @@ -630,6 +635,7 @@ public SessionResultsBundle getSessionResultsForUser(
// generate comment giver name visibility table
commentVisibilityTable.put(frc.getId(), frcLogic.isNameVisibleToUser(frc, relatedResponse, userEmail, roster));
}
RequestTracer.checkRemainingTime();

List<FeedbackResponseAttributes> existingResponses = new ArrayList<>(relatedResponsesMap.values());
List<FeedbackResponseAttributes> missingResponses = Collections.emptyList();
Expand All @@ -639,6 +645,7 @@ public SessionResultsBundle getSessionResultsForUser(
instructor, responseGiverVisibilityTable, responseRecipientVisibilityTable, session,
relatedQuestionsMap, existingResponses, roster, section);
}
RequestTracer.checkRemainingTime();

return new SessionResultsBundle(session, relatedQuestionsMap, existingResponses, missingResponses,
responseGiverVisibilityTable, responseRecipientVisibilityTable, relatedCommentsMap,
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/teammates/logic/core/StudentsLogic.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import teammates.common.exception.RegenerateStudentException;
import teammates.common.exception.SearchServiceException;
import teammates.common.util.Const;
import teammates.common.util.RequestTracer;
import teammates.storage.api.StudentsDb;

/**
Expand Down Expand Up @@ -333,6 +334,7 @@ private String getTeamInvalidityInfo(List<StudentAttributes> mergedList) {
public void deleteStudentsInCourseCascade(String courseId) {
List<StudentAttributes> studentsInCourse = getStudentsForCourse(courseId);
for (StudentAttributes student : studentsInCourse) {
RequestTracer.checkRemainingTime();
deleteStudentCascade(courseId, student.email);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.cloud.datastore.DatastoreException;
import com.google.rpc.Code;

import teammates.common.exception.DeadlineExceededException;
import teammates.common.exception.EntityDoesNotExistException;
import teammates.common.exception.EntityNotFoundException;
import teammates.common.exception.InvalidHttpParameterException;
Expand Down Expand Up @@ -41,6 +42,9 @@ JsonResult execute() {
if (error.equals(NullPointerException.class.getSimpleName())) {
throw new NullPointerException("NullPointerException testing");
}
if (error.equals(DeadlineExceededException.class.getSimpleName())) {
throw new DeadlineExceededException();
}
if (error.equals(DatastoreException.class.getSimpleName())) {
throw new DatastoreException(Code.DEADLINE_EXCEEDED_VALUE, "DatastoreException testing",
Code.DEADLINE_EXCEEDED.name());
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/teammates/ui/webapi/EnrollStudentsAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import teammates.common.exception.InvalidParametersException;
import teammates.common.exception.UnauthorizedAccessException;
import teammates.common.util.Const;
import teammates.common.util.RequestTracer;
import teammates.ui.output.EnrollStudentsData;
import teammates.ui.output.StudentsData;
import teammates.ui.request.StudentsEnrollRequest;
Expand Down Expand Up @@ -73,7 +74,8 @@ JsonResult execute() {
existingStudents.stream().map(StudentAttributes::getEmail).collect(Collectors.toSet());
List<StudentAttributes> enrolledStudents = new ArrayList<>();
List<EnrollStudentsData.EnrollErrorResults> failToEnrollStudents = new ArrayList<>();
studentsToEnroll.forEach(student -> {
for (StudentAttributes student : studentsToEnroll) {
RequestTracer.checkRemainingTime();
if (existingStudentsEmail.contains(student.email)) {
// The student has been enrolled in the course.
StudentAttributes.UpdateOptions updateOptions =
Expand Down Expand Up @@ -103,7 +105,7 @@ JsonResult execute() {
exception.getMessage()));
}
}
});
}
return new JsonResult(new EnrollStudentsData(new StudentsData(enrolledStudents), failToEnrollStudents));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import teammates.common.exception.TeammatesException;
import teammates.common.util.EmailWrapper;
import teammates.common.util.Logger;
import teammates.common.util.RequestTracer;

/**
* Cron job: schedules feedback session closed emails to be sent.
Expand All @@ -19,6 +20,7 @@ JsonResult execute() {
List<FeedbackSessionAttributes> sessions = logic.getFeedbackSessionsClosedWithinThePastHour();

for (FeedbackSessionAttributes session : sessions) {
RequestTracer.checkRemainingTime();
List<EmailWrapper> emailsToBeSent = emailGenerator.generateFeedbackSessionClosedEmails(session);
try {
taskQueuer.scheduleEmailsForSending(emailsToBeSent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import teammates.common.exception.TeammatesException;
import teammates.common.util.EmailWrapper;
import teammates.common.util.Logger;
import teammates.common.util.RequestTracer;

/**
* Cron job: schedules feedback session closing emails to be sent.
Expand All @@ -19,6 +20,7 @@ JsonResult execute() {
List<FeedbackSessionAttributes> sessions = logic.getFeedbackSessionsClosingWithinTimeLimit();

for (FeedbackSessionAttributes session : sessions) {
RequestTracer.checkRemainingTime();
List<EmailWrapper> emailsToBeSent = emailGenerator.generateFeedbackSessionClosingEmails(session);
try {
taskQueuer.scheduleEmailsForSending(emailsToBeSent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import teammates.common.exception.TeammatesException;
import teammates.common.util.EmailWrapper;
import teammates.common.util.Logger;
import teammates.common.util.RequestTracer;

/**
* Cron job: schedules feedback session opening emails to be sent.
Expand All @@ -19,6 +20,7 @@ JsonResult execute() {
List<FeedbackSessionAttributes> sessions = logic.getFeedbackSessionsWhichNeedOpenEmailsToBeSent();

for (FeedbackSessionAttributes session : sessions) {
RequestTracer.checkRemainingTime();
List<EmailWrapper> emailsToBeSent = emailGenerator.generateFeedbackSessionOpeningEmails(session);
try {
taskQueuer.scheduleEmailsForSending(emailsToBeSent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;

import teammates.common.datatransfer.attributes.FeedbackSessionAttributes;
import teammates.common.util.RequestTracer;

/**
* Cron job: schedules feedback session published emails to be sent.
Expand All @@ -14,6 +15,7 @@ JsonResult execute() {
List<FeedbackSessionAttributes> sessions =
logic.getFeedbackSessionsWhichNeedAutomatedPublishedEmailsToBeSent();
for (FeedbackSessionAttributes session : sessions) {
RequestTracer.checkRemainingTime();
taskQueuer.scheduleFeedbackSessionPublishedEmail(session.getCourseId(), session.getFeedbackSessionName());
}
return new JsonResult("Successful");
Expand Down
Loading

0 comments on commit 6484257

Please sign in to comment.