3 Stimmen

Herausforderung von asynchronem Code, der tornado.gen.Task betrifft

Ich habe zahlreiche tornado.web.RequestHandler-Klassen, die autorisierten Zugriff mit id- und Zugriffsschlüssel-Secure-Cookies testen. Ich greife asynchron auf mongodb zu und verwende Inline-Callbacks mit gen.Task. Ich habe Schwierigkeiten herauszufinden, wie ich den wiederholten Code aufgrund seiner Asynchronität auslagern kann. Wie kann ich das tun?

class MyHandler(RequestHandler):
    @tornado.web.asynchronous
    @gen.engine
    def get(self):
        id = self.get_secure_cookie('id', None)
        accesskey = self.get_secure_cookie('accesskey', None)
        if not id or not accesskey:
            self.redirect('/a_public_area')
            return
        try:
            # in bson id Format konvertieren, um auf mongodb zuzugreifen
            bson.objectid.ObjectId(id)
        except:
            # wenn keine gültige Objekt-ID
            self.redirect('/a_public_area')
            return
        found_id, error = yield gen.Task(asyncmong_client_inst.collection.find_one, 
            {'_id': id, 'accesskey': accesskey}, fields={'_id': 1})
        if error['error']:
            raise HTTPError(500)
            return
        if not found_id[0]:
            self.redirect('/a_public_area')
            return

        # es folgt der eigentliche Geschäftscode

Ich würde gerne den obigen Code in eine Funktion auslagern, die möglicherweise einen HTTP-Statuscode zurückgibt.

3voto

semarjt Punkte 31

Vielleicht ein Dekorateur (nicht getestet oder sonstiges, nur einige Ideen)

def säubern(fn):
    def _säubern(self, *args, **kwargs):
        id = self.get_secure_cookie('id', None)
        accesskey = self.get_secure_cookie('accesskey', None)
        if not id or not accesskey:
            self.redirect('/a_public_area')
            return
        try:
            # in bson id Format konvertieren, um auf mongodb zuzugreifen
            bson.objectid.ObjectId(id)
        except:
            # wenn keine gültige Objekt-ID
            self.redirect('/a_public_area')
            return
        return fn(self, *args, **kwargs)
    return _säubern

weiß nicht, ob Sie den check_errors mit der Geschäftslogik funktionieren lassen können..aber vielleicht..

def fehler_prüfen(fn):
   def _fehler_prüfen(*args, **kwargs)
      found_id, error = fn(*args, **kwargs)
      if error['error']:
         raise HTTPError(500)
         return
      if not found_id[0]:
         self.redirect('/a_public_area')
         return
   return _fehler_prüfen

dann

Klasse MyHandler(RequestHandler):
    @tornado.web.asynchronous
    @gen.engine
    @säubern
    @fehler_prüfen #..O.o Dekorateure
    def get(self):
        found_id, error = yield gen.Task(asyncmong_client_inst.collection.find_one, 
              {'_id': id, 'accesskey': accesskey}, fields={'_id': 1})
        return found_id, error

3voto

Nikolay Fominyh Punkte 8448

Tornado hat den Dekorator @tornado.web.authenticated. Lass uns ihn verwenden.

class BaseHandler(RequestHandler):
   def get_login_url(self):
        return u"/a_public_area"

    @gen.engine #Nicht sicher über diesen Schritt
    def get_current_user(self):
        id = self.get_secure_cookie('id', None)
        accesskey = self.get_secure_cookie('accesskey', None)
        if not id or not accesskey:
            return False

        #Sind Sie sicher, dass Sie dies benötigen?
        try:
            # In bson ObjectId-Format konvertieren, um auf MongoDB zuzugreifen
            bson.objectid.ObjectId(id)
        except:
            # Wenn es keine gültige Objekt-ID ist
            return False

        #Ich glaube nicht, dass Sie eine asynchrone Abfrage zum Authentifizieren von MongoDB benötigen. Wenn es nicht funktioniert, ersetzen Sie es durch einen synchronen Aufruf
        found_id, error = yield gen.Task(asyncmong_client_inst.collection.find_one, 
            {'_id': id, 'accesskey': accesskey}, fields={'_id': 1})

        if error['error']:
            raise HTTPError(500)

        if not found_id[0]:
            return False

        return found_id

class MyHandler(BaseHandler):
    @tornado.web.asynchronous
    @tornado.web.authenticated
    @gen.engine
    def get(self):
        # Hier folgt echter Business-Code

Überall gen zu verwenden - keine gute Praxis. Es kann diese Welt in ein großes Spaghetti verwandeln. Denken Sie darüber nach.

2voto

Simon Radford Punkte 301

Ich würde gerne dieses allgemeine Problem mit gen.Task ansprechen, nämlich dass das Auslagern von Code entweder unmöglich oder extrem umständlich ist.

Sie können "yield gen.Task(...)" nur innerhalb der get() oder post() Methode verwenden. Wenn Sie möchten, dass get() eine andere Funktion foo() aufruft und die Arbeit in foo() erledigt, na ja: Das können Sie nicht, es sei denn, Sie möchten alles als Generator schreiben und sie auf eine umständliche Weise verketten. Wenn Ihr Projekt größer wird, wird dies zu einem riesigen Problem.

Das ist eine viel bessere Alternative: https://github.com/mopub/greenlet-tornado

Wir haben dies verwendet, um eine große synchrone Codebasis in Tornado zu konvertieren, mit fast keinen Änderungen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X