Приложение Python, развернутое в Google-App-Engine, редко выдает исключение

Я развернул сайт на Google-App-Engine с Python.

Так как GAE не гарантирует "keep-alive", я реализовал сервер без сохранения состояния:

  1. При каждом изменении внутренних переменных они немедленно сохраняются в базе данных GQL.

  2. При каждом запуске процесса все внутренние переменные загружаются из базы данных GQL.

У меня есть сценарий, который редко выдает исключение, и я не смог отследить его:

  • Клиент отправляет синхронный запрос AJAX POST.

  • Сервер создает сеанс и отправляет уникальный идентификатор сеанса в ответе.

  • Клиент отправляет синхронный запрос 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()

Само исключение указывает на незаконный доступ к sessions словарь с использованием sessionId ключ. По моим наблюдениям, это происходит только тогда, когда последовательность клиент-сервер, описанная в начале этого вопроса, инициируется после того, как сервер "спит" в течение относительно длительного периода времени (например, несколько дней или около того). Это может дать какой-то ключ к пониманию источника этой проблемы, хотя я не могу ее увидеть.

Мои вопросы:

  1. Что-то явно не так с моим дизайном?

  2. Кто-нибудь сталкивался с подобной проблемой на GAE?

  3. Кто-нибудь видит очевидное решение или даже метод отладки, который может помочь понять эту проблему?

Спасибо

1 ответ

Решение

Вы ошибочно полагаете, что все запросы обрабатываются одним и тем же экземпляром. Это совсем не так: GAE, как и большинство сред хостинга, не дает никаких гарантий относительно того, какой серверный процесс обработает любой запрос.

Ваша реализация использует переменную уровня модуля, myServer, который является экземпляром класса со своими собственными переменными экземпляра. Но у каждого серверного процесса будет свой собственный экземпляр myServer, и они не будут разделены между процессами: поэтому запись словаря, созданная в одном запросе, не обязательно будет существовать в секунду.

Вам нужно будет найти способы сохранения этих данных между экземплярами. На самом деле, именно для этого и предназначен хранилище данных; если вы беспокоитесь о накладных расходах, вам следует изучить использование memcache.

Другие вопросы по тегам