crossbario / autobahn-python

WebSocket and WAMP in Python for Twisted and asyncio
https://crossbar.io/autobahn
MIT License
2.48k stars 766 forks source link

Until when component.stop is supposed to block ? #1173

Open rdebroiz opened 5 years ago

rdebroiz commented 5 years ago

After one call stop on a component this will return once the session (if any) has left the realm, but not until it got fully disconnected from the WAMP router.

    comp = Component(transports=conf["transports"], realm=conf["realm"])

    comp_ready = asyncio.Event()
    comp_disconnected = asyncio.Event()

    @comp.on_ready
    async def on_ready(*args, **kwargs):
        print("ready")
        comp_ready.set()

    @comp.on_leave
    async def on_leave(*args, **kwargs):
        print("leaving")

    @comp.on_disconnect
    async def on_disconnect(*args, **kwargs):
        print("disconnecting")
        comp_disconnected.set()

    async def stop():
        await comp_ready.wait()
        print("stopping")
        await comp.stop()  # or just comp.stop(), same result
        print("stopped")
        await comp_disconnected.wait()

    async def start_and_stop(loop):
        # start the component, stop it when it's ready, 
        # wait for the session to be disconnected.
        await asyncio.gather(
            asyncio.ensure_future(comp.start(loop), loop=loop), 
            stop()
        )

    txaio.use_asyncio()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(start_and_stop(loop))

Output expected:

ready
stopping
leaving
disconnecting
stopped

but got:

ready
stopping
leaving
stopped
disconnecting

Looking at the code it might be by design (I'm a little bit lost within all the callbacks, does session.leave return after on_leave handlers has been resolved or does it wait for the on_disconnect handlers as well ?): https://github.com/crossbario/autobahn-python/blob/278fb3880bb9209c8c76baa3d2cba9725f7ce446/autobahn/wamp/component.py#L702-L716

Anyway it make it hard to properly stop the asyncio loop only once every component completed all their scheduled task as their is no easy way to wait for them, as stated here "Event loop stopped before Future completed" : https://github.com/crossbario/autobahn-python/blob/278fb3880bb9209c8c76baa3d2cba9725f7ce446/autobahn/asyncio/component.py#L388-L394

ie: No easy way to stop the loop once every components are done because in the current state there are still pending on_disconnect tasks when components are considered done.

rdebroiz commented 5 years ago

might be related to : https://github.com/crossbario/autobahn-python/issues/1123#issuecomment-469939527