我已經在Python-App-Engine上部署了一個網站。部署在Google-App-Engine上的Python應用程序很少引發異常
由於GAE不保證「保活」,我實現了一個無狀態服務器:
在內部變量的每一個變化,他們會立即存入GQL資料庫。
無論何時啓動進程,所有內部變量都從GQL數據庫加載。
我有很少拋出異常的情況下,我一直沒能追查:
客戶端發送一個同步AJAX POST請求。
服務器創建會話並在響應中發送唯一的會話ID。
客戶端以session-ID作爲參數發送同步AJAX GET請求。
服務器在響應中發送一些文本消息。
由於客戶端請求是同步的,整個序列也是同步的。
這裏是我的服務器內的相關映射:
from webapp2 import WSGIApplication
from Handler import MyRequestHandler
app = WSGIApplication([
('/request1' ,MyRequestHandler), # post request
('/request2(.*)',MyRequestHandler), # get request
])
下面是相關請求處理我的服務器中:
from webapp2 import RequestHandler
from Server import MyServer
myServer = MyServer()
class MyRequestHandler(RequestHandler):
def post(self):
try:
if self.request.path.startswith('/request1'):
sessionId = myServer.GetNewSessionId()
self.SendContent('text/plain',sessionId)
except Exception,error:
self.SendError(error)
def get(self,sessionId):
try:
if self.request.path.startswith('/request2'):
textMessage = myServer.GetMsg(sessionId)
self.SendContent('text/plain',textMessage)
except Exception,error:
self.SendError(error)
def SendContent(self,contentType,contentData):
self.response.set_status(200)
self.response.headers['content-type'] = contentType
self.response.headers['cache-control'] = 'no-cache'
self.response.write(contentData)
def SendError(self,error):
self.response.set_status(500)
self.response.write(error.message)
這裏是內部實現的我服務器:
class MyServer():
def __init__(self):
self.sessions = SessionsTable.ReadSessions()
def GetNewSessionId(self):
while True:
sessionId = ... # a 16-digit random number
if SessionsTable.ReserveSession(sessionId):
self.sessions[sessionId] = ... # a text message
SessionsTable.WriteSession(self.sessions,sessionId)
return sessionId
def GetMsg(self,sessionId):
return self.sessions[sessionId]
最後,這裏是我的服務器中的數據的基礎保養:
from google.appengine.ext import db
class SessionsTable(db.Model):
message = db.TextProperty()
@staticmethod
def ReadSessions():
sessions = {}
for session in SessionsTable.all():
sessions[session.key().name()] = session.message
return sessions
@staticmethod
@db.transactional
def ReserveSession(sessionId):
if not SessionsTable.get_by_key_name(sessionId):
SessionsTable(key_name=sessionId,message='').put()
return True
return False
@staticmethod
def WriteSession(sessions,sessionId):
SessionsTable(key_name=sessionId,message=sessions[sessionId]).put()
@staticmethod
def EraseSession(sessionId):
SessionsTable.get_by_key_name(sessionId).delete()
例外本身表明使用sessionId
鍵sessions
詞典的非法訪問。根據我的觀察,只有當服務器在「睡眠」了相當長的時間(如幾天左右)之後啓動此問題開始時描述的客戶機 - 服務器序列時纔會發生。它可能會提供某種線索來解決這個問題的根源,儘管我無法看到它。
我的問題:
有什麼明顯的錯誤與我的設計?
有沒有人在GAE上遇到類似的問題?
有沒有人看到一個明顯的解決方案,甚至可能有助於理解這個問題的調試方法?
感謝
使用類級別的變量可能是一個壞主意。如果你啓用了線程,那麼你可能會泄露信息。 –
你是指'class SessionsTable'嗎?我沒有這個類的實例,所以這裏不應該有任何問題,對吧?或者你的意思是全局變量'myServer'可能存在問題,它沒有得到正確保護?我沒有使用任何線程,所以我有理由「擔心」GAE會隱式創建它們嗎?謝謝 –
所有這些都可能是一個問題。如果啓用了線程,則appengine將隱含地創建線程來爲每個請求提供服務(如果實例正在快速響應)。所以你必須設計你的應用程序是線程安全的。除非可以共享,否則不要在模塊級別存儲事物,也不要將其存儲爲類屬性。即它可以作爲共享數據的實例級緩存。 –