hynek-urban / rocketchat-async

asyncio-based Python wrapper for the Rocket.Chat Realtime API.
MIT License
11 stars 9 forks source link

An ability to gracefully stop run_forever() #13

Closed mao73a closed 1 week ago

mao73a commented 2 weeks ago

I am using this library in my project https://github.com/mao73a/rocket.icon and I would like to have possibility to stop run_forever() gracefully. I have the app with tray icon and I need to spawn rocketchat-async in a separate thread. I would like to be able to stop this thread somehow, but currently when I cancel the thread, I receive an error that "Task was destroyed but it is pending!." I am new to python programming, but could _runforever have _run_for_xseconds version with a timeout parameter? It would stop processing after a specified amount of time, making it possible to check in my thread main loop, if a stop event was set from outside, and to end the thread gracefully.

hynek-urban commented 1 week ago

@mao73a I think you should be able to use Python's task cancelling. E.g. like this:

while True:
    task = asyncio.create_task(rc.run_forever())
    await asyncio.sleep(1)
    if external_event_arrived_in_the_meantime:
        task.cancel()
        break()

Or call task.cancel() directly in response to a callback tied to the event.

Let me know in case this doesn't solve your use case.

mao73a commented 1 week ago

Hi, thank you for your answer. I have tried your solution but it uses /await /keywor which enforces me to put it inside /async /function and it seems I can't do that, because I am using pystray library (windows tray). This is old library using Threads instead asyncio approach. Fortunatelly I have found workaroung with the help chat gpt, which enables me to start asyncio process from inside old good Thread by doing this:

asyncdefmonitor_subscriptions_websocket(address, username, password): whilesome_stop_event: try: rc=monitor_subscriptions_websocket() awaitrc.start(address, username, password)

subscribe...

awaitrc.run_forever()             ... defmonitor_asyncio_subscriptions_websocket(): asyncio_loop=asyncio.new_event_loop() asyncio.set_event_loop(asyncio_loop) try: asyncio_loop.run_until_complete(monitor_subscriptions_websocket()) threading.Thread(target=monitor_asyncio_subscriptions_websocket).start()

In the meantime... In order to be able to stop /rc.run_forever() /function, I did some modifications inside your library file: /dispatcher.py: _process_incoming/ function and I modified infinite loop to be an event listening loop. This is working fine so far. I am still developing my little project and I am testing it. After I finish, I plan to create a pull request to  rocketchat-async with my changes, in hope you will aprove it.

I  hope I was clear enough and that my explanations make a sense for you. I am not an expert python developer. I am Oracle DB developer for living and I am doing this python project for my own educational purposes mainly, plus I hate generic RocketChat tray icon as being too distracting in my everyday work.

Best regards, Marek

W dniu 12.07.2024 o 19:11, Hynek Urban pisze:

@mao73a https://github.com/mao73a I think you should be able to use Python's task cancelling. E.g. like this:

|while True: task = asyncio.create_task(rc.run_forever()) await asyncio.sleep(1) if external_event_arrived_in_the_meantime: task.cancel() break() |

Or call |task.cancel()| directly in response to a callback tied to the event.

Let me know in case this doesn't solve your use case.

— Reply to this email directly, view it on GitHub https://github.com/hynek-urban/rocketchat-async/issues/13#issuecomment-2225990795, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHG4GIDF7J5QLJSB6YAAOODZMAE4JAVCNFSM6AAAAABKPPGZXOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMRVHE4TANZZGU. You are receiving this because you were mentioned.Message ID: @.***>

hynek-urban commented 1 week ago

Cześć :)

The formatting in your message seems to be a bit broken. In any case, if you're in a synchronous context, you can also adapt the example above simply like this:

task = asyncio.create_task(rc.run_forever())
while True:
    time.sleep(1)
    if external_event_arrived_in_the_meantime:
        task.cancel()
        break()
mao73a commented 1 week ago

Hi Hynek, thank you so much for this solution. It has solved my problem. My previous changes to rocketchat-sync library are unnecesary now. Works like charm!

Regards, Marek

W dniu 12.07.2024 o 21:43, Hynek Urban pisze:

Cześć :)

The formatting in your message seems to be a bit broken. In any case, if you're in a synchronous context, you can also adapt the example above simply like this:

task = asyncio.create_task(rc.run_forever()) while True: time.sleep(1) if external_event_arrived_in_the_meantime: task.cancel() break()

— Reply to this email directly, view it on GitHub https://github.com/hynek-urban/rocketchat-async/issues/13#issuecomment-2226248428, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHG4GICTI4T2PZ22HUHHRBTZMAWXLAVCNFSM6AAAAABKPPGZXOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMRWGI2DQNBSHA. You are receiving this because you were mentioned.Message ID: @.***>