如何在GAE任务队列中执行OAuth需求操作? [英] How to do OAuth-requiring operations in a GAE Task Queue?
问题描述
我有一个简单的Google App Engine应用,其中包含一个更新YouTube播放列表的 / update
页面。它看起来像这样:
类UpdatePage(webapp2.RequestHandler):
@ decorator.oauth_required
def get(self):
update_result = self.update_playlist()
...
routes = [('/ update',UpdatePage),
(decorator.callback_path,decorator.callback_handler())]
app = webapp2.WSGIApplication(routes,debug = True)
它按预期工作,并且 update_playlist()
方法完成它的工作,但事实证明在某些情况下它可以运行很长时间时间,导致 DeadlineExceededError
。所以在阅读了可用的选项后,我想到了 Task Queue API是要走的路(正确?),我试图使用它,遵循在Python中使用推送队列指南。
→总之,我将 UpdatePage
分成 UpdatePageHandler
+ UpdatePageWorker
:
类UpdateHandlerPage(webapp2.RequestHandler):
@ decorator.oauth_required
def get (self):
taskqueue.add(url ='/ updateworker')
类UpdateWorkerPage(webapp2.RequestHandler):
def post(self):
update_result = self.update_playlist()
...
routes = [('/ update',UpdateHandlerPage),
('/ updateworker',UpdateWorkerPage),
(decorator.callback_path,decorator.callback_handler())]
app = webapp2.WSGIApplication(routes,debug = True)
不幸的是,在完成拆分之后,似乎我的OAuth2装饰器不再执行其任务:
INFO 2013-05-30 17:08:53,971 discovery.py:709]请求的网址:https://www.googleapis.com/youtube/v3/playlists?alt=json&part=snippet% 2Cstatus
警告2013-05-30 17:08:53,975 urlfetch_stub.py:480]从URLFetch请求中剥离禁止标头:['content-length']
INFO 2013-05-30 17:08: 54,351 client.py:493]刷新401
INFO 2013-05-30 17:08:54,361 appengine.py:276] make:Got type< class'google.appengine.api.datastore_types.Blob >
INFO 2013-05-30 17:08:54,363 appengine.py:289] validate:Got type< class'oauth2client.client.OAuth2Credentials'>
INFO 2013-05-30 17:08:54,364 client.py:680]刷新access_token
INFO 2013-05-30 17:08:54,746 client.py:699]无法检索访问令牌: {
error:invalid_grant
}
INFO 2013-05-30 17:08:54,757 appengine.py:276] make:Got type< class'google.appengine。 api.datastore_types.Blob'>
INFO 2013-05-30 17:08:54,759 appengine.py:289] validate:Got type< class'oauth2client.client.OAuth2Credentials'>
INFO 2013-05-30 17:08:54,761 appengine.py:289] validate:Got type< class'oauth2client.client.OAuth2Credentials'>
INFO 2013-05-30 17:08:54,762 appengine.py:265] get:Got type< class'oauth2client.appengine.CredentialsModel'>
如果不是装饰 UpdateHandlerPage:get
我装饰了 UpdateWorkerPage:post
,我得到了一个无限的失败循环:
INFO 2013-05-30 17:24:31,307 discovery.py:190]请求的网址:https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest?userIp = 127.0.0.1
INFO 2013-05-30 17:24:34,960 dev_appserver.py:3105]GET / update HTTP / 1.1200 -
INFO 2013-05-30 17:24:35,060 dev_appserver.py:3105 ]POST / updateworker HTTP / 1.1302 -
警告2013-05-30 17:24:35,065 taskqueue_stub.py:1980]任务task1执行失败。此任务将在0.100秒后重试
INFO 2013-05-30 17:24:35,240 dev_appserver.py:3105]POST / updateworker HTTP / 1.1302 -
警告2013-05-30 17: 24:35,245 taskqueue_stub.py:1980]任务task1未能执行。此任务将在0.200秒内重试
...
我该怎么办?感谢您的帮助!
由于任务队列任务将由您的应用程序产生,因此原始请求将通过发送。特别是,通过 更新:(这是在原文后添加的。)由于没有cookie, 不是试图从装饰器中获取当前用户,您最好将App Engine用户ID传递给您的任务。首先获取当前用户(在您装饰的方法中): 然后通过沿着任务中的App Engine用户标识 然后在你的任务中,你可以检索那个 并使用它获取该用户的凭据就像在装饰器中完成: I have a simple Google App Engine app that includes a It works as expected and the → In short, I split Unfortunately, after doing the split it seems my OAuth2 decorator no longer does its job: And if instead of decorating What can I do? Thanks for your help! Since the Task Queue task will be spawned by your application, none of the headers from your original request will be sent through. In particular, the UPDATE: (This was added after the original post.) As a result of no cookies, the Instead of trying to get the current user from the decorator, you are better off passing along the App Engine User ID to your task. First get the current user (within your decorated method): and then pass along the App Engine User ID in the task Then within your task, you can retrieve grab that and use it to get that user's credentials as is done in the decorator:
这篇关于如何在GAE任务队列中执行OAuth需求操作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! SACSID
cookie为您的应用程序标识用户的 Cookies 标题(由App Engine Users API )。
标识用户的SACSID
cookie不会在那里,因此 decorator.oauth_required
指定将强制重定向(即HTTP 302
) EVERY 运行cron作业。
from google.appengine.api导入用户
#保证不要被装饰者设为无
current_user = users.get_current_user()
import urllib
query_string = urllib.urlencode({'user_id': current_user.user_id()})
taskqueue.add(url ='/ updateworker?'+ query_string)
user_id
#这是在查询字符串
中添加的'user_id'user_id = self.request.get('user_id')
from oauth2client.appengine import CredentialsModel $ b $ from oauth2client.appengine import StorageByKeyName
#您正在使用OAuth2Decorator的默认值
#您的上面的代码是
credentials = StorageByKeyName(
CredentialsModel,user_id,'credentials').get()
/update
page which updates a YouTube playlist. It looks like this:class UpdatePage(webapp2.RequestHandler):
@decorator.oauth_required
def get(self):
update_result = self.update_playlist()
...
routes = [('/update', UpdatePage),
(decorator.callback_path, decorator.callback_handler())]
app = webapp2.WSGIApplication(routes, debug=True)
update_playlist()
method does its job, but it turns out that under some circumstances it can run for a pretty long time, resulting in a DeadlineExceededError
. So after reading about the available options, I figured the Task Queue API is the way to go (right?) and I'm trying to use it, following the Using Push Queues in Python guide.UpdatePage
into UpdatePageHandler
+ UpdatePageWorker
:class UpdateHandlerPage(webapp2.RequestHandler):
@decorator.oauth_required
def get(self):
taskqueue.add(url='/updateworker')
class UpdateWorkerPage(webapp2.RequestHandler):
def post(self):
update_result = self.update_playlist()
...
routes = [('/update', UpdateHandlerPage),
('/updateworker', UpdateWorkerPage),
(decorator.callback_path, decorator.callback_handler())]
app = webapp2.WSGIApplication(routes, debug=True)
INFO 2013-05-30 17:08:53,971 discovery.py:709] URL being requested: https://www.googleapis.com/youtube/v3/playlists?alt=json&part=snippet%2Cstatus
WARNING 2013-05-30 17:08:53,975 urlfetch_stub.py:480] Stripped prohibited headers from URLFetch request: ['content-length']
INFO 2013-05-30 17:08:54,351 client.py:493] Refreshing due to a 401
INFO 2013-05-30 17:08:54,361 appengine.py:276] make: Got type <class 'google.appengine.api.datastore_types.Blob'>
INFO 2013-05-30 17:08:54,363 appengine.py:289] validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
INFO 2013-05-30 17:08:54,364 client.py:680] Refreshing access_token
INFO 2013-05-30 17:08:54,746 client.py:699] Failed to retrieve access token: {
"error" : "invalid_grant"
}
INFO 2013-05-30 17:08:54,757 appengine.py:276] make: Got type <class 'google.appengine.api.datastore_types.Blob'>
INFO 2013-05-30 17:08:54,759 appengine.py:289] validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
INFO 2013-05-30 17:08:54,761 appengine.py:289] validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
INFO 2013-05-30 17:08:54,762 appengine.py:265] get: Got type <class 'oauth2client.appengine.CredentialsModel'>
UpdateHandlerPage:get
I decorate UpdateWorkerPage:post
, I get an infinite failure loop instead:INFO 2013-05-30 17:24:31,307 discovery.py:190] URL being requested: https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest?userIp=127.0.0.1
INFO 2013-05-30 17:24:34,960 dev_appserver.py:3105] "GET /update HTTP/1.1" 200 -
INFO 2013-05-30 17:24:35,060 dev_appserver.py:3105] "POST /updateworker HTTP/1.1" 302 -
WARNING 2013-05-30 17:24:35,065 taskqueue_stub.py:1980] Task task1 failed to execute. This task will retry in 0.100 seconds
INFO 2013-05-30 17:24:35,240 dev_appserver.py:3105] "POST /updateworker HTTP/1.1" 302 -
WARNING 2013-05-30 17:24:35,245 taskqueue_stub.py:1980] Task task1 failed to execute. This task will retry in 0.200 seconds
...
Cookies
header identifying your user via the SACSID
cookie for your application (provided by the App Engine Users API).SACSID
cookie identifying the user won't be there, hence the decorator.oauth_required
designation will force a redirect (which is HTTP 302
) EVERY time the cron job runs.from google.appengine.api import users
# Guaranteed not to be None by the decorator
current_user = users.get_current_user()
import urllib
query_string = urllib.urlencode({'user_id': current_user.user_id()})
taskqueue.add(url='/updateworker?' + query_string)
user_id
# This is the 'user_id' you appended in the query string
user_id = self.request.get('user_id')
from oauth2client.appengine import CredentialsModel
from oauth2client.appengine import StorageByKeyName
# This assumes you are using the defaults for OAuth2Decorator,
# which your above code is
credentials = StorageByKeyName(
CredentialsModel, user_id, 'credentials').get()