Python Forum
an uncatchable asyncio exception from in 3.12.2 but not 3.11.5
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
an uncatchable asyncio exception from in 3.12.2 but not 3.11.5
#1
For the following code:
from asyncio import create_task, run as aiorun, sleep as aiosleep
from asyncio import get_event_loop, get_running_loop
from os import fork, getpid, pipe, waitpid, WNOHANG
from os import close as osclose, read as osread, write as oswrite
from time import sleep

class Worker(object):
    class exctype(Exception): pass
    sleep_seconds = 0.1
    async def work(self) -> int | None:
        try: return await self.fork_and_wait()
        except Exception as exc: print('413124', exc)
        #task = create_task(self.fork_and_wait())
        #while not task.done() and not task.cancelled(): await aiosleep(0.1)
        #print('4124', task.exception)
        #try: return task.result()
        #except Exception as exc:
        #    print('95425', task, exc)

    async def fork_and_wait(self) -> int:
        print('fork_and_wait.0')
        pipe_fds = pipe()
        if (subpid := fork()) == 0: self.subprocess(pipe_fds)
        elif subpid < 0: raise self.exctype('fork failed')
        osclose(pipe_fds[1])
        loop = get_event_loop()
        self.line_cache = b''
        loop.add_reader(pipe_fds[0], self.pipe_reader, pipe_fds[0], subpid)
        while True:
            try: subpid0, status = waitpid(subpid, WNOHANG)
            except ChildProcessError as exc: break
            if subpid == subpid0: break
            await aiosleep(self.sleep_seconds)
        loop.remove_reader(pipe_fds[0])
        osclose(pipe_fds[0])
        return status
    def pipe_reader(self, rfd: int, subpid: int) -> None:
        if not (rbody := osread(rfd, 1024)): return
        print('xxxx', rbody)
    def subprocess(self, pipe_fds: tuple[int]) -> int:
        osclose(pipe_fds[0])
        for idx in range(4):
            oswrite(pipe_fds[1], ('xzy: %u\n' % idx).encode('utf-8'))
            sleep(0.2)
        osclose(pipe_fds[1])
        exit(0)
async def main_worker():
    task = create_task(Worker().work())
    #task = create_task(Worker().fork_and_wait())
    while not task.done() and not task.cancelled(): await aiosleep(0.1)
    print('frwrqwer', task.exception())
    try: result = task.result()
    except SystemExit as exc:
        print('kkkk', task, exc)
    except Worker.exctype as exc:
        print('zzzz', task, exc)
    except Exception as exc:
        print('aaaa', task, exc)
    print('cccc', result)

# To use the following code, works in 3.11.5, but not in 3.12.2
#loop = get_event_loop()
#loop.run_until_complete(main_worker())
# To use the following code, do not work in 3.11.5 and 3.12.2
aiorun(main_worker())
As the comment in the code, it works for me when run_until_complete is used in 3.11.5, but it does not works anymore in 3.12.2.
The following exception is issued and can not be catched:
Output:
fork_and_wait.0 xxxx b'xzy: 0\n' xxxx b'xzy: 1\n' xxxx b'xzy: 2\n' xxxx b'xzy: 3\n' Task exception was never retrieved
Error:
future: <Task finished name='Task-2' coro=<Worker.work() done, defined at /home/wangli/aifire/aifire.draft/aiopy/aioexit.py:10> exception=SystemExit(0)> Traceback (most recent call last): File "/home/wangli/aifire/aifire.draft/aiopy/aioexit.py", line 66, in <module> aiorun(main_worker()) File "/opt/py3.aifire/lib/python3.12/asyncio/runners.py", line 194, in run return runner.run(main) ^^^^^^^^^^^^^^^^ File "/opt/py3.aifire/lib/python3.12/asyncio/runners.py", line 118, in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/py3.aifire/lib/python3.12/asyncio/base_events.py", line 672, in run_until_complete self.run_forever() File "/opt/py3.aifire/lib/python3.12/asyncio/base_events.py", line 639, in run_forever self._run_once() File "/opt/py3.aifire/lib/python3.12/asyncio/base_events.py", line 1985, in _run_once handle._run() File "/opt/py3.aifire/lib/python3.12/asyncio/events.py", line 88, in _run self._context.run(self._callback, *self._args) File "/home/wangli/aifire/aifire.draft/aiopy/aioexit.py", line 11, in work try: return await self.fork_and_wait() ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/wangli/aifire/aifire.draft/aiopy/aioexit.py", line 23, in fork_and_wait if (subpid := fork()) == 0: self.subprocess(pipe_fds) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/wangli/aifire/aifire.draft/aiopy/aioexit.py", line 46, in subprocess exit(0) File "<frozen _sitebuiltins>", line 26, in __call__ SystemExit: 0
Output:
frwrqwer None cccc 0
Yes, I known the dangerous about fork in async functions, but it should be very convenient if something can be passed through fork from parent to subprocess directly.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  During handling of the above exception, another exception occurred Skaperen 7 26,925 Dec-21-2018, 10:58 AM
Last Post: Gribouillis

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020