SEBSERV-449 better timeouts and name search on moodle side
This commit is contained in:
		
							parent
							
								
									9d7ef0452f
								
							
						
					
					
						commit
						3ce025c4b1
					
				
					 5 changed files with 38 additions and 15 deletions
				
			
		|  | @ -76,7 +76,7 @@ public class ClientHttpRequestFactoryService { | ||||||
|             final ClientCredentialService clientCredentialService, |             final ClientCredentialService clientCredentialService, | ||||||
|             @Value("${sebserver.http.client.connect-timeout:15000}") final int connectTimeout, |             @Value("${sebserver.http.client.connect-timeout:15000}") final int connectTimeout, | ||||||
|             @Value("${sebserver.http.client.connection-request-timeout:20000}") final int connectionRequestTimeout, |             @Value("${sebserver.http.client.connection-request-timeout:20000}") final int connectionRequestTimeout, | ||||||
|             @Value("${sebserver.http.client.read-timeout:20000}") final int readTimeout) { |             @Value("${sebserver.http.client.read-timeout:30000}") final int readTimeout) { | ||||||
| 
 | 
 | ||||||
|         this.environment = environment; |         this.environment = environment; | ||||||
|         this.clientCredentialService = clientCredentialService; |         this.clientCredentialService = clientCredentialService; | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ import java.util.stream.Collectors; | ||||||
| import org.joda.time.DateTime; | import org.joda.time.DateTime; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  | import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.core.env.Environment; | import org.springframework.core.env.Environment; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
|  | @ -53,16 +54,19 @@ public class QuizLookupServiceImpl implements QuizLookupService { | ||||||
|     private final UserService userService; |     private final UserService userService; | ||||||
|     private final LmsSetupDAO lmsSetupDAO; |     private final LmsSetupDAO lmsSetupDAO; | ||||||
|     private final AsyncRunner asyncRunner; |     private final AsyncRunner asyncRunner; | ||||||
|  |     private final long fetchedDataValiditySeconds; | ||||||
| 
 | 
 | ||||||
|     public QuizLookupServiceImpl( |     public QuizLookupServiceImpl( | ||||||
|             final UserService userService, |             final UserService userService, | ||||||
|             final LmsSetupDAO lmsSetupDAO, |             final LmsSetupDAO lmsSetupDAO, | ||||||
|             final AsyncService asyncService, |             final AsyncService asyncService, | ||||||
|             final Environment environment) { |             final Environment environment, | ||||||
|  |             @Value("${sebserver.webservice.lms.datafetch.validity.seconds:600}") final long fetchedDataValiditySeconds) { | ||||||
| 
 | 
 | ||||||
|         this.userService = userService; |         this.userService = userService; | ||||||
|         this.lmsSetupDAO = lmsSetupDAO; |         this.lmsSetupDAO = lmsSetupDAO; | ||||||
|         this.asyncRunner = asyncService.getAsyncRunner(); |         this.asyncRunner = asyncService.getAsyncRunner(); | ||||||
|  |         this.fetchedDataValiditySeconds = fetchedDataValiditySeconds; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|  | @ -158,7 +162,10 @@ public class QuizLookupServiceImpl implements QuizLookupService { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (!asyncLookup.isValid(filterMap)) { |         if (!asyncLookup.isValid(filterMap)) { | ||||||
|             this.lookups.remove(userId); |             final AsyncLookup removed = this.lookups.remove(userId); | ||||||
|  |             if (removed != null) { | ||||||
|  |                 removed.cancel(); | ||||||
|  |             } | ||||||
|             this.createNewAsyncLookup(userId, filterMap, lmsAPITemplateSupplier); |             this.createNewAsyncLookup(userId, filterMap, lmsAPITemplateSupplier); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -198,7 +205,12 @@ public class QuizLookupServiceImpl implements QuizLookupService { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             final LookupFilterCriteria criteria = new LookupFilterCriteria(filterMap); |             final LookupFilterCriteria criteria = new LookupFilterCriteria(filterMap); | ||||||
|             final AsyncLookup asyncLookup = new AsyncLookup(userInstitutionId, userId, criteria, buffers); |             final AsyncLookup asyncLookup = new AsyncLookup( | ||||||
|  |                     userInstitutionId, | ||||||
|  |                     userId, | ||||||
|  |                     criteria, | ||||||
|  |                     buffers, | ||||||
|  |                     this.fetchedDataValiditySeconds); | ||||||
| 
 | 
 | ||||||
|             if (log.isDebugEnabled()) { |             if (log.isDebugEnabled()) { | ||||||
|                 log.debug("Create new AsyncLookup: user={} criteria={}", userId, criteria); |                 log.debug("Create new AsyncLookup: user={} criteria={}", userId, criteria); | ||||||
|  | @ -278,18 +290,21 @@ public class QuizLookupServiceImpl implements QuizLookupService { | ||||||
|         final Collection<AsyncQuizFetchBuffer> asyncBuffers; |         final Collection<AsyncQuizFetchBuffer> asyncBuffers; | ||||||
|         final long timeCreated; |         final long timeCreated; | ||||||
|         long timeCompleted = Long.MAX_VALUE; |         long timeCompleted = Long.MAX_VALUE; | ||||||
|  |         private final long fetchedDataValiditySeconds; | ||||||
| 
 | 
 | ||||||
|         public AsyncLookup( |         public AsyncLookup( | ||||||
|                 final long institutionId, |                 final long institutionId, | ||||||
|                 final String userId, |                 final String userId, | ||||||
|                 final LookupFilterCriteria lookupFilterCriteria, |                 final LookupFilterCriteria lookupFilterCriteria, | ||||||
|                 final Collection<AsyncQuizFetchBuffer> asyncBuffers) { |                 final Collection<AsyncQuizFetchBuffer> asyncBuffers, | ||||||
|  |                 final long fetchedDataValiditySeconds) { | ||||||
| 
 | 
 | ||||||
|             this.institutionId = institutionId; |             this.institutionId = institutionId; | ||||||
|             this.userId = userId; |             this.userId = userId; | ||||||
|             this.lookupFilterCriteria = lookupFilterCriteria; |             this.lookupFilterCriteria = lookupFilterCriteria; | ||||||
|             this.asyncBuffers = asyncBuffers; |             this.asyncBuffers = asyncBuffers; | ||||||
|             this.timeCreated = Utils.getMillisecondsNow(); |             this.timeCreated = Utils.getMillisecondsNow(); | ||||||
|  |             this.fetchedDataValiditySeconds = fetchedDataValiditySeconds; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         LookupResult getAvailable() { |         LookupResult getAvailable() { | ||||||
|  | @ -307,10 +322,7 @@ public class QuizLookupServiceImpl implements QuizLookupService { | ||||||
| 
 | 
 | ||||||
|         boolean isUpToDate() { |         boolean isUpToDate() { | ||||||
|             final long now = Utils.getMillisecondsNow(); |             final long now = Utils.getMillisecondsNow(); | ||||||
|             if (now - this.timeCreated > 5 * Constants.MINUTE_IN_MILLIS) { |             if (now - this.timeCreated > this.fetchedDataValiditySeconds * Constants.SECOND_IN_MILLIS) { | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|             if (now - this.timeCompleted > Constants.MINUTE_IN_MILLIS) { |  | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|  |  | ||||||
|  | @ -61,6 +61,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils.Courses; | import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils.Courses; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils.CoursesPlugin; | import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils.CoursesPlugin; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils.MoodleUserDetails; | import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils.MoodleUserDetails; | ||||||
|  | import io.micrometer.core.instrument.util.StringUtils; | ||||||
| 
 | 
 | ||||||
| public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess implements CourseAccessAPI { | public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess implements CourseAccessAPI { | ||||||
| 
 | 
 | ||||||
|  | @ -118,7 +119,7 @@ public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess impleme | ||||||
|                 environment.getProperty( |                 environment.getProperty( | ||||||
|                         "sebserver.webservice.circuitbreaker.moodleRestCall.blockingTime", |                         "sebserver.webservice.circuitbreaker.moodleRestCall.blockingTime", | ||||||
|                         Long.class, |                         Long.class, | ||||||
|                         Constants.SECOND_IN_MILLIS * 20), |                         Constants.SECOND_IN_MILLIS * 30), | ||||||
|                 environment.getProperty( |                 environment.getProperty( | ||||||
|                         "sebserver.webservice.circuitbreaker.moodleRestCall.timeToRecover", |                         "sebserver.webservice.circuitbreaker.moodleRestCall.timeToRecover", | ||||||
|                         Long.class, |                         Long.class, | ||||||
|  | @ -184,10 +185,11 @@ public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess impleme | ||||||
|                 quizFromTime = DateTime.now(DateTimeZone.UTC).minusYears(this.cutoffTimeOffset); |                 quizFromTime = DateTime.now(DateTimeZone.UTC).minusYears(this.cutoffTimeOffset); | ||||||
|             } |             } | ||||||
|             final Predicate<QuizData> quizFilter = LmsAPIService.quizFilterPredicate(filterMap); |             final Predicate<QuizData> quizFilter = LmsAPIService.quizFilterPredicate(filterMap); | ||||||
|  |             final String quizName = filterMap.getQuizName(); | ||||||
| 
 | 
 | ||||||
|             while (!asyncQuizFetchBuffer.finished && !asyncQuizFetchBuffer.canceled) { |             while (!asyncQuizFetchBuffer.finished && !asyncQuizFetchBuffer.canceled) { | ||||||
|                 try { |                 try { | ||||||
|                     fetchQuizzesPage(page, quizFromTime, asyncQuizFetchBuffer, quizFilter); |                     fetchQuizzesPage(page, quizFromTime, quizName, asyncQuizFetchBuffer, quizFilter); | ||||||
|                     page++; |                     page++; | ||||||
|                 } catch (final Exception e) { |                 } catch (final Exception e) { | ||||||
|                     log.error("Unexpected error while trying to fetch moodle quiz page: {}", page, e); |                     log.error("Unexpected error while trying to fetch moodle quiz page: {}", page, e); | ||||||
|  | @ -371,6 +373,7 @@ public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess impleme | ||||||
|     private void fetchQuizzesPage( |     private void fetchQuizzesPage( | ||||||
|             final int page, |             final int page, | ||||||
|             final DateTime quizFromTime, |             final DateTime quizFromTime, | ||||||
|  |             final String nameCondition, | ||||||
|             final AsyncQuizFetchBuffer asyncQuizFetchBuffer, |             final AsyncQuizFetchBuffer asyncQuizFetchBuffer, | ||||||
|             final Predicate<QuizData> quizFilter) throws JsonParseException, JsonMappingException, IOException { |             final Predicate<QuizData> quizFilter) throws JsonParseException, JsonMappingException, IOException { | ||||||
| 
 | 
 | ||||||
|  | @ -382,7 +385,7 @@ public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess impleme | ||||||
|                 : lmsSetup.lmsApiUrl + Constants.URL_PATH_SEPARATOR + MOODLE_QUIZ_START_URL_PATH; |                 : lmsSetup.lmsApiUrl + Constants.URL_PATH_SEPARATOR + MOODLE_QUIZ_START_URL_PATH; | ||||||
| 
 | 
 | ||||||
|         final Collection<CourseData> fetchCoursesPage = |         final Collection<CourseData> fetchCoursesPage = | ||||||
|                 fetchCoursesPage(restTemplate, quizFromTime, page, this.pageSize); |                 fetchCoursesPage(restTemplate, quizFromTime, nameCondition, page, this.pageSize); | ||||||
|         // finish if page is empty (no courses left |         // finish if page is empty (no courses left | ||||||
|         if (fetchCoursesPage.isEmpty()) { |         if (fetchCoursesPage.isEmpty()) { | ||||||
|             asyncQuizFetchBuffer.finish(); |             asyncQuizFetchBuffer.finish(); | ||||||
|  | @ -408,6 +411,7 @@ public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess impleme | ||||||
|     private Collection<CourseData> fetchCoursesPage( |     private Collection<CourseData> fetchCoursesPage( | ||||||
|             final MoodleAPIRestTemplate restTemplate, |             final MoodleAPIRestTemplate restTemplate, | ||||||
|             final DateTime quizFromTime, |             final DateTime quizFromTime, | ||||||
|  |             final String nameCondition, | ||||||
|             final int page, |             final int page, | ||||||
|             final int size) throws JsonParseException, JsonMappingException, IOException { |             final int size) throws JsonParseException, JsonMappingException, IOException { | ||||||
| 
 | 
 | ||||||
|  | @ -422,13 +426,19 @@ public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess impleme | ||||||
|             final long defaultCutOff = Utils.toUnixTimeInSeconds( |             final long defaultCutOff = Utils.toUnixTimeInSeconds( | ||||||
|                     DateTime.now(DateTimeZone.UTC).minusYears(this.cutoffTimeOffset)); |                     DateTime.now(DateTimeZone.UTC).minusYears(this.cutoffTimeOffset)); | ||||||
|             final long cutoffDate = (filterDate < defaultCutOff) ? filterDate : defaultCutOff; |             final long cutoffDate = (filterDate < defaultCutOff) ? filterDate : defaultCutOff; | ||||||
|             final String sqlCondition = String.format( |             String sqlCondition = String.format( | ||||||
|                     SQL_CONDITION_TEMPLATE, |                     SQL_CONDITION_TEMPLATE, | ||||||
|                     String.valueOf(cutoffDate), |                     String.valueOf(cutoffDate), | ||||||
|                     String.valueOf(filterDate)); |                     String.valueOf(filterDate)); | ||||||
|             final String fromElement = String.valueOf(page * size); |             final String fromElement = String.valueOf(page * size); | ||||||
|             final LinkedMultiValueMap<String, String> attributes = new LinkedMultiValueMap<>(); |             final LinkedMultiValueMap<String, String> attributes = new LinkedMultiValueMap<>(); | ||||||
| 
 | 
 | ||||||
|  |             if (StringUtils.isNotBlank(nameCondition)) { | ||||||
|  |                 sqlCondition = sqlCondition + " AND (m.name LIKE '" + | ||||||
|  |                         Utils.toSQLWildcard(nameCondition) + | ||||||
|  |                         "')"; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             // Note: courseid[]=0 means all courses. Moodle don't like empty parameter |             // Note: courseid[]=0 means all courses. Moodle don't like empty parameter | ||||||
|             attributes.add(PARAM_COURSE_ID_ARRAY, "0"); |             attributes.add(PARAM_COURSE_ID_ARRAY, "0"); | ||||||
|             attributes.add(PARAM_SQL_CONDITIONS, sqlCondition); |             attributes.add(PARAM_SQL_CONDITIONS, sqlCondition); | ||||||
|  |  | ||||||
|  | @ -18,7 +18,7 @@ spring.datasource.hikari.leakDetectionThreshold=2000 | ||||||
| 
 | 
 | ||||||
| sebserver.http.client.connect-timeout=15000 | sebserver.http.client.connect-timeout=15000 | ||||||
| sebserver.http.client.connection-request-timeout=10000 | sebserver.http.client.connection-request-timeout=10000 | ||||||
| sebserver.http.client.read-timeout=20000 | sebserver.http.client.read-timeout=30000 | ||||||
| sebserver.webservice.distributed.updateInterval=1000 | sebserver.webservice.distributed.updateInterval=1000 | ||||||
| sebserver.webservice.distributed.connectionUpdate=2000 | sebserver.webservice.distributed.connectionUpdate=2000 | ||||||
| sebserver.webservice.clean-db-on-startup=false | sebserver.webservice.clean-db-on-startup=false | ||||||
|  | @ -52,7 +52,7 @@ sebserver.webservice.api.pagination.maxPageSize=500 | ||||||
| sebserver.webservice.lms.openedx.api.token.request.paths=/oauth2/access_token | sebserver.webservice.lms.openedx.api.token.request.paths=/oauth2/access_token | ||||||
| sebserver.webservice.lms.moodle.api.token.request.paths= | sebserver.webservice.lms.moodle.api.token.request.paths= | ||||||
| sebserver.webservice.lms.address.alias=lms.mockup.com=lms.address.alias | sebserver.webservice.lms.address.alias=lms.mockup.com=lms.address.alias | ||||||
| sebserver.webservice.cache.moodle.course.pageSize=10 | sebserver.webservice.cache.moodle.course.pageSize=250 | ||||||
| 
 | 
 | ||||||
| springdoc.api-docs.enabled=true | springdoc.api-docs.enabled=true | ||||||
| springdoc.swagger-ui.enabled=true | springdoc.swagger-ui.enabled=true | ||||||
|  |  | ||||||
|  | @ -83,6 +83,7 @@ sebserver.webservice.lms.moodle.prependShortCourseName=true | ||||||
| sebserver.webservice.lms.moodle.fetch.cutoffdate.yearsBeforeNow=2 | sebserver.webservice.lms.moodle.fetch.cutoffdate.yearsBeforeNow=2 | ||||||
| sebserver.webservice.lms.olat.sendAdditionalAttributesWithRestriction=false | sebserver.webservice.lms.olat.sendAdditionalAttributesWithRestriction=false | ||||||
| sebserver.webservice.lms.address.alias= | sebserver.webservice.lms.address.alias= | ||||||
|  | sebserver.webservice.lms.datafetch.validity.seconds=600 | ||||||
| 
 | 
 | ||||||
| sebserver.webservice.proctoring.resetBroadcastOnLeav=true | sebserver.webservice.proctoring.resetBroadcastOnLeav=true | ||||||
| sebserver.webservice.proctoring.zoom.enableWaitingRoom=false | sebserver.webservice.proctoring.zoom.enableWaitingRoom=false | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 anhefti
						anhefti