feat: move XQueueService from the runtime to ProblemBlock

The XQueueService is used only by the ProblemBlock. Therefore, we are moving 
it out of the runtime, and into the ProblemBlock, where it's initialized only 
when it's going to be used.
This commit is contained in:
Piotr Surowiec
2023-06-21 20:08:31 +02:00
committed by GitHub
parent 9e0b59fe87
commit 0137f21627
7 changed files with 74 additions and 169 deletions

View File

@@ -1,13 +1,19 @@
"""
LMS Interface to external queueing system (xqueue)
"""
from typing import Dict, Optional, TYPE_CHECKING
import hashlib
import json
import logging
import requests
import six
from django.conf import settings
from django.urls import reverse
from requests.auth import HTTPBasicAuth
if TYPE_CHECKING:
from xmodule.capa_block import ProblemBlock
log = logging.getLogger(__name__)
dateformat = '%Y%m%d%H%M%S'
@@ -25,7 +31,7 @@ def make_hashkey(seed):
Generate a string key by hashing
"""
h = hashlib.md5()
h.update(six.b(str(seed)))
h.update(str(seed).encode('latin-1'))
return h.hexdigest()
@@ -65,13 +71,13 @@ def parse_xreply(xreply):
return (return_code, content)
class XQueueInterface(object):
class XQueueInterface:
"""
Interface to the external grading system
"""
def __init__(self, url, django_auth, requests_auth=None):
self.url = six.text_type(url)
def __init__(self, url: str, django_auth: Dict[str, str], requests_auth: Optional[HTTPBasicAuth] = None):
self.url = url
self.auth = django_auth
self.session = requests.Session()
self.session.auth = requests_auth
@@ -155,21 +161,17 @@ class XQueueService:
XBlock service providing an interface to the XQueue service.
Args:
construct_callback(callable): function which constructs a fully-qualified callback URL to make xqueue requests.
default_queuename(string): course-specific queue name.
waittime(int): number of seconds to wait between xqueue requests
url(string): base URL for the XQueue service.
django_auth(dict): username and password for the XQueue service.
basic_auth(array or None): basic authentication credentials, if needed.
block: The `ProblemBlock` instance.
"""
def __init__(self, construct_callback, default_queuename, waittime, url, django_auth, basic_auth=None):
requests_auth = requests.auth.HTTPBasicAuth(*basic_auth) if basic_auth else None
self._interface = XQueueInterface(url, django_auth, requests_auth)
def __init__(self, block: 'ProblemBlock'):
basic_auth = settings.XQUEUE_INTERFACE.get('basic_auth')
requests_auth = HTTPBasicAuth(*basic_auth) if basic_auth else None
self._interface = XQueueInterface(
settings.XQUEUE_INTERFACE['url'], settings.XQUEUE_INTERFACE['django_auth'], requests_auth
)
self._construct_callback = construct_callback
self._default_queuename = default_queuename.replace(' ', '_')
self._waittime = waittime
self._block = block
@property
def interface(self):
@@ -178,23 +180,33 @@ class XQueueService:
"""
return self._interface
@property
def construct_callback(self):
def construct_callback(self, dispatch: str = 'score_update') -> str:
"""
Returns the function to construct the XQueue callback.
Return a fully qualified callback URL for external queueing system.
"""
return self._construct_callback
relative_xqueue_callback_url = reverse(
'xqueue_callback',
kwargs=dict(
course_id=str(self._block.scope_ids.usage_id.context_key),
userid=str(self._block.scope_ids.user_id),
mod_id=str(self._block.scope_ids.usage_id),
dispatch=dispatch,
),
)
xqueue_callback_url_prefix = settings.XQUEUE_INTERFACE.get('callback_url', settings.LMS_ROOT_URL)
return xqueue_callback_url_prefix + relative_xqueue_callback_url
@property
def default_queuename(self):
def default_queuename(self) -> str:
"""
Returns the default queue name for the current course.
"""
return self._default_queuename
course_id = self._block.scope_ids.usage_id.context_key
return f'{course_id.org}-{course_id.course}'.replace(' ', '_')
@property
def waittime(self):
def waittime(self) -> int:
"""
Returns the number of seconds to wait in between calls to XQueue.
"""
return self._waittime
return settings.XQUEUE_WAITTIME_BETWEEN_REQUESTS