-
-
Notifications
You must be signed in to change notification settings - Fork 32.8k
Description
Bug report
Bug description:
Ok, so, the issue I'm facing is happening when using playwright-python
, which uses asyncio
under the hood (which is where the problem seems to lie according to my investigation).
What happens is the following:
playwright-python
launches a node process using asyncio
using code as:
self._proc = await asyncio.create_subprocess_exec(
str(self._driver_executable),
"run-driver",
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=_get_stderr_fileno(),
limit=32768,
env=env,
startupinfo=startupinfo,
)
Then, later on it goes on to finish the process, but after finishing the process asyncio
never appears to get a notification that the process finishes and it gets stuck in the close
forever due to that.
Turning on debug on the asyncio event loop shows messages such as:
DEBUG:asyncio:<IocpProactor overlapped#=2 result#=0> is running after closing for 81.1 seconds
and it never leaves the asyncio IocpProactor.close
because the while self._cache:
always has 2 elements there.
The elements are:
{1744745874048: (
<_WaitHandleFuture cancelled handle=0x424 signaled>,
<_overlapped.Overlapped object at 0x000001963AF54270>, 0, <function IocpProactor._wait_for_handle.<locals>.finish_wait_for_handle at 0x000001963AF54160>),
1744791716192: (
<_WaitCancelFuture pending created at py39\lib\asyncio\windows_events.py:699 handle=0x438 signaled wait_handle=0x1963a2f4580>,
<_overlapped.Overlapped object at 0x000001963DB0C150>, 0, <function IocpProactor._wait_for_handle.<locals>.finish_wait_for_handle at 0x000001963DB0CD30>)
}
Those seem to be created at:
File "py39\lib\site-packages\playwright\_impl\_transport.py", line 123, in connect
self._proc = await asyncio.create_subprocess_exec(
File "py39\lib\asyncio\subprocess.py", line 236, in create_subprocess_exec
transport, protocol = await loop.subprocess_exec(
File "py39\lib\asyncio\base_events.py", line 1676, in subprocess_exec
transport = await self._make_subprocess_transport(
File "py39\lib\asyncio\windows_events.py", line 394, in _make_subprocess_transport
transp = _WindowsSubprocessTransport(self, protocol, args, shell,
File "py39\lib\asyncio\base_subprocess.py", line 36, in __init__
self._start(args=args, shell=shell, stdin=stdin, stdout=stdout,
File "py39\lib\asyncio\windows_events.py", line 904, in _start
f = self._loop._proactor.wait_for_handle(int(self._proc._handle))
File "py39\lib\asyncio\windows_events.py", line 675, in wait_for_handle
return self._wait_for_handle(handle, timeout, False)
File "py39\lib\asyncio\windows_events.py", line 687, in _wait_for_handle
traceback.print_stack()
and
File "py39\lib\asyncio\base_events.py", line 634, in run_until_complete
self.run_forever()
File "py39\lib\asyncio\windows_events.py", line 321, in run_forever
super().run_forever()
File "py39\lib\asyncio\base_events.py", line 601, in run_forever
self._run_once()
File "py39\lib\asyncio\base_events.py", line 1869, in _run_once
event_list = self._selector.select(timeout)
File "py39\lib\asyncio\windows_events.py", line 439, in select
self._poll(timeout)
File "py39\lib\asyncio\windows_events.py", line 825, in _poll
f.set_result(value)
File "py39\lib\asyncio\windows_events.py", line 166, in set_result
self._unregister_wait()
File "py39\lib\asyncio\windows_events.py", line 242, in _unregister_wait
self._event_fut = self._proactor._wait_cancel(self._event,
File "py39\lib\asyncio\windows_events.py", line 678, in _wait_cancel
fut = self._wait_for_handle(event, None, True)
File "py39\lib\asyncio\windows_events.py", line 687, in _wait_for_handle
traceback.print_stack()
This doesn't always happen. The only difference I can see from both cases is that in one case the callback
registered in _WindowsSubprocessTransport
is called when it works and when it fails it's not called, but on both cases the subprocess exited.
So, the actual bug seems to be that the function registered in the _WindowsSubprocessTransport
:
f = self._loop._proactor.wait_for_handle(int(self._proc._handle))
f.add_done_callback(callback)
is never called in one case but it's called in the other, but I can't see a reason for that to happen (and so far I couldn't find any workaround that doesn't involve doing really nasty things to asyncio internals).
Not sure if it makes any difference, but this is on a Windows server 2022. Reproduced with Python 3.9, 3.10 and 3.11 (unable to check it for 3.12 as it misses some other dependencies needed).
CPython versions tested on:
3.9, 3.10, 3.11
Operating systems tested on:
Windows
Metadata
Metadata
Assignees
Labels
Projects
Status