Google App Engine Python 多个用户共享的持久会话
Google App Engine Python Persistent Session Shared by Multiple Users
我想做什么(背景信息)?
我的任务是创建一个 google 应用程序引擎应用程序 (Python 2.7),该应用程序引擎应用程序 post 将数据发送到另一台服务器。我尝试连接的服务器的身份验证使用 user:password 来换取 cookie。通过将 cookie 与表单数据一起传递,我可以将 post 数据发送到服务器。我不拥有我 post 访问的服务器,因此无法进行任何更改。每次您请求身份验证 cookie 时,它都会使旧 cookie 失效。所以我坚持 cookie/session 并在它过期时获得一个新的。
我正在尝试解决的问题。
当用户 A 提交表单数据时,cookie 仍然有效。 (处理所有表单数据大约需要 45 秒)
用户 B 正在提交表单数据,但现在 cookie 无效。因此,通过为用户 B 请求一个新的 cookie,我在用户 A 的数据仍在处理时使他们的 cookie 无效。
那么有没有办法 lock/wait 所有请求直到会话完成刷新?或者那会是个坏主意吗?
def get_session(self):
url= self.base_url + "/index.cfm"
form_fields = {
"email": "user@example.com",
"password": "passwerd",
"iStarAPI_fuseaction": "Login"
}
urlfetch.set_default_fetch_deadline(60)
#first we check the datastore if a persistent session exsists
persistent_s = PersistentSession.query(ancestor=ndb.Key(PersistentSession,'SESSION')).fetch()
#ok we found a session in the datastore if its not expired we are going to use that one
if persistent_s:
if persistent_s[0].expires_at > datetime.datetime.utcnow():
return pickle.loads(persistent_s[0].session)
else:
try:
s = requests.Session()
s.post(url, data=form_fields)
date_now = datetime.datetime.utcnow()
delta = datetime.timedelta(seconds=1500)
session_expiry_time = date_now + delta
persistent_s[0].expires_at = session_expiry_time
persistent_s[0].session = pickle.dumps(s)
persistent_s[0].put()
return s
except Exception,e:
logging.error(e)
#there was no session in the datastore or it was expired we need a new one
else:
try:
s = requests.Session()
s.post(url, data=form_fields)
date_now = datetime.datetime.utcnow()
delta = datetime.timedelta(seconds=1500)
session_expiry_time = date_now + delta
persistent_s = PersistentSession(parent=ndb.Key(PersistentSession, 'SESSION'))
persistent_s.expires_at = session_expiry_time
persistent_s.session = pickle.dumps(s)
persistent_s.put()
#this is the important login session (all requests use the same session until it expires)
return s
except Exception, e:
logging.error(e)
A 'lock' 可以是 'close to expiring' 标志加上活动表单提交的计数器(提交开始时递增,结束时递减)。该标志可以是一个简单的过期时间检查,但计数器需要在数据库中。
如果设置了标志且计数器不为零,则阻止开始新的 postings(例如使用 while 循环)。只有最后一个活动 posting 在递减计数器(从 1 到 0)之前实际刷新 cookie。
然而,锁定 'live' 请求时间过长可能会导致您的应用实例因超过时间配额而被终止(例如,如果平均 45 秒偶尔超过 60 秒)。
一个可能的解决方案是将实际的 postings 推送到任务队列中。如果 posting 被锁定,您只需要 'fail' 所有任务执行,GAE 将自动重试它们(一段时间)- 一旦刷新 cookie 并解除锁定,任务应该自动通过。缺点:由于任务失败,这会在日志中产生一些噪音。非常高的流量也可能导致超过任务队列限制。
另一种可能性是在 post 接近过期并且 progress/waiting 中没有其他 post 时先发制人地刷新 cookie。缺点:不能保证有效 - 如果请求流足够高以致于在到期前找不到这样的 'idle' 个点。
我能想到的在流量高峰期间处理锁定的唯一可靠方法是使用数据存储来 'buffer' posting 作业,您将在解除锁定后重播(再次任务队列将是触发重放操作的简单方法。
我想做什么(背景信息)? 我的任务是创建一个 google 应用程序引擎应用程序 (Python 2.7),该应用程序引擎应用程序 post 将数据发送到另一台服务器。我尝试连接的服务器的身份验证使用 user:password 来换取 cookie。通过将 cookie 与表单数据一起传递,我可以将 post 数据发送到服务器。我不拥有我 post 访问的服务器,因此无法进行任何更改。每次您请求身份验证 cookie 时,它都会使旧 cookie 失效。所以我坚持 cookie/session 并在它过期时获得一个新的。
我正在尝试解决的问题。 当用户 A 提交表单数据时,cookie 仍然有效。 (处理所有表单数据大约需要 45 秒) 用户 B 正在提交表单数据,但现在 cookie 无效。因此,通过为用户 B 请求一个新的 cookie,我在用户 A 的数据仍在处理时使他们的 cookie 无效。
那么有没有办法 lock/wait 所有请求直到会话完成刷新?或者那会是个坏主意吗?
def get_session(self):
url= self.base_url + "/index.cfm"
form_fields = {
"email": "user@example.com",
"password": "passwerd",
"iStarAPI_fuseaction": "Login"
}
urlfetch.set_default_fetch_deadline(60)
#first we check the datastore if a persistent session exsists
persistent_s = PersistentSession.query(ancestor=ndb.Key(PersistentSession,'SESSION')).fetch()
#ok we found a session in the datastore if its not expired we are going to use that one
if persistent_s:
if persistent_s[0].expires_at > datetime.datetime.utcnow():
return pickle.loads(persistent_s[0].session)
else:
try:
s = requests.Session()
s.post(url, data=form_fields)
date_now = datetime.datetime.utcnow()
delta = datetime.timedelta(seconds=1500)
session_expiry_time = date_now + delta
persistent_s[0].expires_at = session_expiry_time
persistent_s[0].session = pickle.dumps(s)
persistent_s[0].put()
return s
except Exception,e:
logging.error(e)
#there was no session in the datastore or it was expired we need a new one
else:
try:
s = requests.Session()
s.post(url, data=form_fields)
date_now = datetime.datetime.utcnow()
delta = datetime.timedelta(seconds=1500)
session_expiry_time = date_now + delta
persistent_s = PersistentSession(parent=ndb.Key(PersistentSession, 'SESSION'))
persistent_s.expires_at = session_expiry_time
persistent_s.session = pickle.dumps(s)
persistent_s.put()
#this is the important login session (all requests use the same session until it expires)
return s
except Exception, e:
logging.error(e)
A 'lock' 可以是 'close to expiring' 标志加上活动表单提交的计数器(提交开始时递增,结束时递减)。该标志可以是一个简单的过期时间检查,但计数器需要在数据库中。
如果设置了标志且计数器不为零,则阻止开始新的 postings(例如使用 while 循环)。只有最后一个活动 posting 在递减计数器(从 1 到 0)之前实际刷新 cookie。
然而,锁定 'live' 请求时间过长可能会导致您的应用实例因超过时间配额而被终止(例如,如果平均 45 秒偶尔超过 60 秒)。
一个可能的解决方案是将实际的 postings 推送到任务队列中。如果 posting 被锁定,您只需要 'fail' 所有任务执行,GAE 将自动重试它们(一段时间)- 一旦刷新 cookie 并解除锁定,任务应该自动通过。缺点:由于任务失败,这会在日志中产生一些噪音。非常高的流量也可能导致超过任务队列限制。
另一种可能性是在 post 接近过期并且 progress/waiting 中没有其他 post 时先发制人地刷新 cookie。缺点:不能保证有效 - 如果请求流足够高以致于在到期前找不到这样的 'idle' 个点。
我能想到的在流量高峰期间处理锁定的唯一可靠方法是使用数据存储来 'buffer' posting 作业,您将在解除锁定后重播(再次任务队列将是触发重放操作的简单方法。