2

The essence of the question is: Is it possible to use WAMP notifications in a Django application supporting both Python 2.7 and 3.4, considering that code should be running and only be interrupted if a Remote Procedure Call is made? (That is, it's not only waiting for a RPC to come)

How we want to use WAMP: the program has a Javascript frontend with a Python/Django backend. One of the things we do is start a function in the backend when a button in the frontend is clicked. This sometimes takes too much time though, so we allow the user to cancel that by clicking another button. This one makes a Remote Procedure Call, which will cause the function to stop earlier (it changes a variable that is checked in the function). There might be other needs for RPC or Pub/Sub in the future too.

We got it working with Python 2.7 using the autobahn_sync module, but it uses Twisted, which hasn't yet been fully ported to Python 3.x. That's why we would need another way of getting our WAMP notification to work on 3.x.

asyncio is supported and from the crossbar documentation it seemed it could be used instead of Twisted, but we can't get it to work without blocking the code that should be running in parallel (code is added below). And there doesn't seem to be something like autobahn_sync using asyncio instead of Twisted.

We're new to WAMP and there might be something we're missing.

Here's the code (with Python 3.4) we're testing using asyncio. It's blocking the rest of the function:

from asyncio import coroutine, new_event_loop, set_event_loop
from autobahn.asyncio.wamp import ApplicationSession, ApplicationRunner

class MyComponent(ApplicationSession):
        @wamp.register("com.function.cancel")
        def cancel(self):
            print("called cancel procedure")
            # do things here
            return "Canceled"

        @coroutine
        def onJoin(self, details):
            res = yield from self.register(self)
            print("{} procedures registered.".format(len(res)))

def function_triggered_in_frontend():
    loop = new_event_loop()
    set_event_loop(loop)
    runner = ApplicationRunner(url=u"ws://localhost:8080/ws", realm=u"realm1")
    runner.run(MyComponent)
    # and now the function should continue working on other things, but does't because it doesn't return from runner.run().
    print("do stuff")

How can we register to the topic and return from the runner.run call? In the Python 2.7 test, with autobahn_sync we could simply do:

from autobahn_sync import register, run, AlreadyRunningError
@register('com.function.cancel')
def cancel_generate_jobs():
    print("called cancel procedure")
    @register('com.function.cancel')
    # def cancel_generate_jobs():

def function_triggered_in_frontend():
    try:
        run(realm=u"realm1")
    except AlreadyRunningError:
        logger.info('AutbahnSync instance already started.')
    # and then the code would continue being processed here, as we want
RiggsFolly
  • 93,638
  • 21
  • 103
  • 149
Denise
  • 21
  • 2
  • For long-running tasks in Django, you should really look into Celery rather than trying to manage event loops. – Daniel Roseman May 09 '16 at 11:47
  • Thanks for looking into the question! The event loop is created because asyncio only automatically creates an event loop in the main thread. Since this is not the main thread, we need to explicitly create and set the event loop. Also we don't want to manage this task but allow the user to send a call from the frontend (javascript) to the registered function in the backend and return a confirmation message... as far as I know Celery can't do that, right? – Denise May 09 '16 at 13:29

0 Answers0