Reusing session for many requests

#1

Hello,

Let’s look for the very simple piece of code:

class MyClient:
   def __init__():
    self.component = autobahn.asyncio.Component()
    self.session = None
    
    @self.component.on_join
    def on_join(session, details):
       self.session = session

  def my_rpc_call1():
      asyncio.run_coroutine_threadsafe(session.call(...), loop=self.event_loop)

  def my_rpc_call2():
      asyncio.run_coroutine_threadsafe(session.call(...), loop=self.event_loop)

My question is:
Is it ok to share the established session between different (possibly) concurrent calls?. I mean, it is possible that MyClient.my_rpc_call1 and MyClient.my_rpc_call2 (and so on) will be called by different threads.

0 Likes

#2

Hi John2,

Usually, you do not need threads to do concurrent programming with an async framework like asyncio. The docs say you’d have to be using run_coroutine_threadsafe from a different thread. So, if you are using threads, can you expand your example to include those? Otherwise, don’t worry about threads (and yes, one session can run multiple calls “at once” without threads).

See https://docs.python.org/3/library/asyncio-task.html#asyncio.run_coroutine_threadsafe

0 Likes

#3

To put my code in another way:

My component:

class MyComponent(ApplicationSession):
   def __init__():
           self.c = None
    @inlineCallbacks
    def onJoin(c, details):
         c.c = c

 async def f1(c):
      return await c.call('any.rpc.method1')

 async def f2(c):
      return await c.call('any.rpc.method2')

My code:

c = MyComponent() 
asyncio.run_coroutine_threadsafe(c.start(), loop=my_event_loop) 
# my_event _loop is running by background thread)
result1 = asyncio.run_coroutine_threadsafe(f1(c), loop=my_event_loop)
result2 = asyncio.run_coroutine_threadsafe(f2(c), loop=my_event_loop)

Is it correct?

0 Likes

#4

I think you don’t need to bother with run_coroutine_threadsafe at all, and just use e.g. asyncio.gather or so on the two futures/coroutines from f1 and f2. Something approximately like: loop.run_until_complete(asyncio.gather([f1(c), f2(c)])).

Note that the Component instance is NOT what is passed to onJoin, it will get a session instance. So that part of the code isn’t quite right. Have you found the examples? https://github.com/crossbario/autobahn-python/tree/master/examples/asyncio/wamp/component (there’s similar ones in the twisted tree of examples too).

There seems to be some confusion in the above about the difference between the Component API (which can be used for a more “functional” approach to writing WAMP code) and the ApplicationSession object (which can be used for a “subclass” approach to writing WAMP code). The e.g. autobahn.asyncio.component.run method can be used to run code written using either approach and ApplicationRunner can be used to run only subclass-style code.

As for the lifecycles: the Component instances live longer than a single WAMP session (e.g. they do re-connections) whereas an ApplicationSession (or subclass) instance lives only exactly as long as a WAMP session does. A WAMP session lives at most as long as the underlying transport connection.

0 Likes

#5

Thanks for your response.

You are obviously right that to the onJoin is passed session object (not component).

I think you don’t need to bother with run_coroutine_threadsafe at all, and just use e.g. asyncio.gather

I actually need that in my use case. However, I would like ask again: is it safe to use it in that way?

0 Likes