【问题标题】:Random DeadlineExceeded errors when using Google Classroom API使用 Google Classroom API 时出现随机 DeadlineExceeded 错误
【发布时间】:2017-05-10 07:31:24
【问题描述】:

我有一个在 GAE (Python) 上运行的应用程序,Google 课堂用户可以在其中导入他/她的课程(学生姓名和名单)。代码分为两部分。首先,我得到该用户所有课程的列表:

directoryauthdecorator = OAuth2Decorator(
approval_prompt='force',
client_id='my_client_id',
client_secret='my_client_secret',
callback_path='/oauth2callback',
scope=[
      'https://www.googleapis.com/auth/classroom.courses',
      'https://www.googleapis.com/auth/classroom.rosters'])

class ClassroomAPI(webapp.RequestHandler):
    @directoryauthdecorator.oauth_required
    def get(self):
        function=self.request.get('function')   
        auth_http = directoryauthdecorator.http()
        service = build("classroom", "v1", http=auth_http)

        if function == "getAllCourses":
            try:

                 results = service.courses().list(pageSize=100,teacherId=users.get_current_user().email(),courseStates="ACTIVE").execute()
                 courses = results.get('courses',[])

                 #PARSE AND RETURN LIST OF COURSES TO USER
            except errors.HttpError, error:
                 #RETURN ERROR


application = webapp.WSGIApplication(
                         [('/classroomAPI', ClassroomAPI),
                         (directoryauthdecorator.callback_path, directoryauthdecorator.callback_handler())],
                         debug=True)

这部分一直有效。然后用户从列表中选择他/她想要导入的课程。选择的课程回传到上面的脚本,执行下一部分:

        if function == "getStudentListForCourse":
            students=[]
            selectedCourses = json.loads(self.request.body)["courses"]
            for course in selectedCourses:
                page_token=None
                while True:
                    params={}
                    params["courseId"]=course["classroomId"]
                    params["pageSize"]=50
                    if page_token:
                        params["pageToken"]=page_token

                    studentList = service.courses().students().list(**params).execute()
                    for student in studentList['students']:
                        students.append(student['profile']['emailAddress'])

                    page_token = studentList.get('nextPageToken')
                    if not page_token:
                        break

            #RETURN STUDENTS

这里的问题是我的日志在studentList = service.courses().students().list(**params).execute() 线上随机报告'DeadlineExceededError',这使得导入过程不可靠。

任何提示将不胜感激。

更新:

我已经尝试过 alpeware 发布的建议,但不幸的是它没有任何作用。

【问题讨论】:

    标签: python google-app-engine google-classroom


    【解决方案1】:

    根据您的通话时长,您会遇到对请求施加的60sec timeout。您无法更改此超时,因为它有助于 App Engine 实现其扩展魔法。

    为了避免超时,我建议使用Push Queue 作为Task Queue 服务的一部分。

    您必须重构代码以适应 UI 中学生列表的异步加载,并将学生列表存储在数据存储中。

    在您的特定用例中,您可以重构代码以使用 deferred library 填充学生列表。

    要启用延迟库,您必须对 app.yaml 进行以下更改 -

    将以下条目添加到您的app.yamlbuiltins 部分:

    - deferred: on
    

    以及同一文件的处理程序部分的以下条目:

    - url: /_ah/queue/deferred
        script: google.appengine.ext.deferred.deferred.application
        login: admin
    

    这里有一些东西可以让你开始重构你的代码以使用延迟库 -

        from util import getStudentList
    
        if function == "getStudentListForCourse":
            credentials = directoryauthdecorator.get_credentials()
            selectedCourses = json.loads(self.request.body)["courses"]
            for course in selectedCourses:
                deferred.defer(getStudentList, course, credentials, None, [])
    

    然后新建一个模块util.py -

         import httplib2
         from google.appengine.api import memcache
    
         def getStudentList(course=None, credentials=None, pageToken=None, students=None):
            http = httplib2.Http(cache=memcache)
            auth_http = credentials.authorize(http)
            service = build("classroom", "v1", http=auth_http)
    
            params = {}
            params["courseId"] = course["classroomId"]
            params["pageSize"] = 50
            if pageToken:
                params["pageToken"] = pageToken
            studentList = service.courses().students().list(**params).execute()
            for student in studentList['students']:
                students.append(student['profile']['emailAddress'])
    
            pageToken = studentList.get('nextPageToken')
            if pageToken:
                return deferred.deferr(getStudentList, course, credentials, pageToken, students)
            # There are no more students for this class.
            # TODO: store students for course
    

    如前所述,当所有任务完成后,您必须更改视图以从数据存储中返回结果。

    如果您还有其他问题,请告诉我,并乐于提供其他建议。

    【讨论】:

    • 感谢您的详细帖子。我现在想知道在这种情况下处理 API 授权的最佳方法是什么。我已经实施了您的建议,但似乎无法在第一次 API 调用之后正确授权。之后我不断收到错误 401 无效凭据。
    • 没问题!我不熟悉课堂 API 细节。您目前如何创建服务以及您传递的凭据是什么?如果它是基于每个用户的,您可以包含 user_id 并根据它检索您的访问令牌。官方 oauth2 客户端有专门用于应用引擎的模型。让我知道并很高兴添加更多详细信息。
    • 我目前正在使用 OAuth2Decorator,如我原始帖子中的第一个代码 sn-p 所示。我将应用程序的客户端 ID 和密码传递给构造函数。
    • Doh 错过了。我编辑了答案以包括传递凭据和在任务队列中构建服务。它应该可以工作,但如果还有其他问题,请告诉我。
    • 有效!非常感谢你,你非常有帮助。我会继续完成整个实现,如果错误得到解决,我会接受答案。
    猜你喜欢
    • 2020-01-14
    • 2017-09-11
    • 2020-11-16
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 2015-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多