Twisted and nested Deferred with inline callbacks in crossbar.io

732 Views Asked by At

I'm relatively new to Twisted and crossbar.io and I'm currently working on some database abstractions using sqlalchemy and alchimia (a layer to use sqlalchemy with twisted). The db abstractions I build so far are working as expected but I get problems when making asynchronous db calls inside my crossbar procedures. I guess that is because i have nested asynchronous calls with the outer call being some crossbar remote procedure and the inner being the database access.

What i want to do is the following:

@inlineCallbacks
def onJoin(self, details):
  ...
  def login(user, password): # <-- outer call
    ...
    db_result = yield db.some_query(user, password) # <-- inner call
    for row in db_result: # <-- need to wait for db_result
      return 'authentication_ticket'
    return 'error'

To be able to authenticate the user i have to wait for the data from the db and then either issue a valid ticket or return an error. Currently I get an error that i cannot iterate over an deferred, because i don't wait for the db query to be finished.

Now, how do i wait inside my login RPC for the inner db call, then authenticate the user and then return. I know it is possible to chain asynchronous calls in twisted, but i don't know how to do this in this special case with crossbar and when my outer function uses the @inlineCallbacks shortcut.

Update:

Tinkering around I now can add a callback to the db query. Unfortunately now I don't know how to pass a return value from the inner function to the outer function (the outer function needs to return the ticket the user gets authenticated with):

@inlineCallbacks
  def onJoin(self, details):
  ...
  def login(user, password): # <-- outer call
    db_result = db.some_query(user, password) # <-- inner call

    def my_callback(query_result):
      if not query_result.is_empty():
        return 'user_ticket' # <-- needs to be returned by outer method

    db_result.addCallback(my_callback)

    return my_callback_result # <-- need something like that

I tried defer.returnValue('user_ticket') inside my callback function but this gives me an error.

1

There are 1 best solutions below

0
On BEST ANSWER

Your problem appears to be that while login is expecting to yield Deferreds, it isn't decorated with @inlineCallbacks.