Oct-25-2023, 04:46 PM
Hi all,
I have a Python script that handles a continuous stream of requests, processing them using asyncio.
I find that the script hangs at times and stops handling new requests.
I believe I found the issue was that the parent task was a weak reference and possibly garage collected before it was completed.
I fixed that issue, but now the code handles only 1 request, then does not respond afterwards to a new request.
The key part of the script is
I added sums_main_task to make the first Task a strong reference, the purpose of which is to create a Task to run the async method sums_server.
Inside sums_server I create a 2nd Task, called sums_task, which calls the method ahandle in class SUMS_Request, which does all the work.
Once ahandle completes (returning True for the final step), the Task sums_task is completed, and the callback _handle_ahandle_throws is called.
This sequence works fine for one request.
When a second request is sent to the script, no log entries appear in the log file and the code doesn't respond.
I was hoping that once the callback invoked by the child Task sums_task was done, control would go back to sums_server and a new request
would be handled.
I suspect that once the callback is invoked by the child and then parent Tasks, the event loop is completed, but control is not passed back to either
the current loop, or a new one. Hence my problem of the script processing only one request.
What's the correct sequence for event loops & Tasks to have run_forever continuously handle new requests as them arrive ?
Thanks,
--Ed
I have a Python script that handles a continuous stream of requests, processing them using asyncio.
I find that the script hangs at times and stops handling new requests.
I believe I found the issue was that the parent task was a weak reference and possibly garage collected before it was completed.
I fixed that issue, but now the code handles only 1 request, then does not respond afterwards to a new request.
The key part of the script is
import asyncio from sums_classes import SUMS_Requests .... sums_loop and sums_sock defined here ... def _handle_ahandle_throws(task: asyncio.Task): try: task.result() return task except asyncio.CancelledError: log.writeInfo(['CancelledError exception raised in ahandle task = %r', task]) pass ... async def sums_server(): conn, client_addr = await sums_loop.sock_accept(sums_sock) <---get conn from socket sr = SUMS_Requests(sums_loop, log) <---instantiate class SUMS_Requests sums_task = sums_loop.create_task(sr.ahandle(conn)) <---handle request all_tasks.add(sums_task) sums_task.add_done_callback(_handle_ahandle_throws) <---callback log.writeInfo(['sums_task done = ' + str(sums_task.done())]) log.writeInfo(['Creating task to await for asyncio coroutine sum server... serving on ' + str(sums_sock)]) sums_main_task = sums_loop.create_task(sum_server()) <---save parent task as strong reference sums_main_task.add_done_callback(_handle_ahandle_throws) <---callback log.writeInfo(['sums main task done = ' + str(sums_main_task.done())]) try: sums_loop.run_forever() <--- should handle continuous requests except KeyboardInterrupt: log.writeInfo(['Received SIGINT from stop script.... shutting down now pid = ' + str(pid)]) sums_loop.close() sums_sock.shutdown(socket.SHUT_RDWR) sums_sock.close() raise KeyboardInterrupt finally: ....The script runs in Python 3.11.4 on RedHat 8.8, my comments for readability in this thread start with <---
I added sums_main_task to make the first Task a strong reference, the purpose of which is to create a Task to run the async method sums_server.
Inside sums_server I create a 2nd Task, called sums_task, which calls the method ahandle in class SUMS_Request, which does all the work.
Once ahandle completes (returning True for the final step), the Task sums_task is completed, and the callback _handle_ahandle_throws is called.
This sequence works fine for one request.
When a second request is sent to the script, no log entries appear in the log file and the code doesn't respond.
I was hoping that once the callback invoked by the child Task sums_task was done, control would go back to sums_server and a new request
would be handled.
I suspect that once the callback is invoked by the child and then parent Tasks, the event loop is completed, but control is not passed back to either
the current loop, or a new one. Hence my problem of the script processing only one request.
What's the correct sequence for event loops & Tasks to have run_forever continuously handle new requests as them arrive ?
Thanks,
--Ed