Open dineshbvadhia opened 3 months ago
I think it will be. This seems to be something going on inside of do_startup_stuff()
. This example works without issues:
import anyio
from asapi import serve
from fastapi import FastAPI
app = FastAPI()
def do_startup_stuff():
print('Doing startup stuff')
async def main():
do_startup_stuff()
await serve(app, 8000)
if __name__ == '__main__':
anyio.run(main)
I don't know what your do_startup_stuff()
is or what add_exception_handler
is
Could you try removing one at a time of do_startup_stuff
and add_exception_handler
and mounting the router to see which one is causing the issue?
At startup the following happens: cli validation, db connection creation and read data which work as expected. The db connection (dao) forms the fastapi dependency DaoDep = Annotated[Dao, Depends(resolve_dao)]
which has been replaced with asapi Injected
. The asapi skeleton code structure is:
from fastapi import FastAPI
import anyio
from asapi import Injected, serve, bind
class Dao:
...
@app.get("/")
async def get(dao: Injected[Dao]):
...
app = FastAPI()
async def main():
do_cli_validation() # works
dao = Dao()
bind(app, Dao, dao)
do_read_data(dao) # works, so dao = Dao() works
await serve(app, 8000)
if __name__ == "__main__":
anyio.run(main)
The startup error is as before. Is the Injected dependency not configured correctly?
The full traceback is:
INFO: Started server process [6840]
INFO: Waiting for application startup.
ERROR: Traceback (most recent call last):
asapi\_signal_handling.py", line 46, in handle_signals
yield stop
asapi\_serve.py", line 21, in serve
await stop.wait()
anyio\_backends\_asyncio.py", line 1662, in wait
await self._event.wait()
asyncio\locks.py", line 213, in wait
await fut
asyncio.exceptions.CancelledError: Cancelled by cancel scope 1d3f7af3a50
During handling of the above exception, another exception occurred:
+ Exception Group Traceback (most recent call last):
| anyio\_backends\_asyncio.py", line 2034, in run
| return runner.run(wrapper())
| ^^^^^^^^^^^^^^^^^^^^^
| asyncio\runners.py", line 118, in run
| return self._loop.run_until_complete(task)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| asyncio\base_events.py", line 653, in run_until_complete
| return future.result()
| ^^^^^^^^^^^^^^^
| anyio\_backends\_asyncio.py", line 2022, in wrapper
| return await func(*args)
| ^^^^^^^^^^^^^^^^^
| server_asapi.py", line 613, in main
| await serve(app, 8000)
| asapi\_serve.py", line 18, in serve
| async with handle_signals() as stop:
| contextlib.py", line 222, in __aexit__
| await self.gen.athrow(typ, value, traceback)
| asapi\_signal_handling.py", line 44, in handle_signals
| async with anyio.create_task_group() as tg:
| anyio\_backends\_asyncio.py", line 680, in __aexit__
| raise BaseExceptionGroup(
| ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
+-+---------------- 1 ----------------
| Traceback (most recent call last):
| asapi\_signal_handling.py", line 17, in _signal_handler
| with anyio.open_signal_receiver(signal.SIGTERM, signal.SIGINT) as signals:
| anyio\_backends\_asyncio.py", line 1805, in __enter__
| self._loop.add_signal_handler(sig, self._deliver, sig)
| asyncio\events.py", line 574, in add_signal_handler
| raise NotImplementedError
| NotImplementedError
+------------------------------------
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
starlette\routing.py", line 741, in lifespan
await receive()
uvicorn\lifespan\on.py", line 137, in receive
return await self.receive_queue.get()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
asyncio\queues.py", line 158, in get
await getter
asyncio.exceptions.CancelledError
from asapi import Injected, serve, bind, validate_injections
Generates the error:
Traceback (most recent call last):
File "...server_asapi.py", line 71, in <module>
from asapi import Injected, serve, bind, validate_injections
ImportError: cannot import name 'validate_injections' from 'asapi' (...asapi\__init__.py)
Do you mean that literally just the imports generate that error for you?
from asapi import Injected, serve, bind, validate_injections
?
That seems very strange: https://github.com/adriangb/asapi/blob/e2ed763efa7c8e0f6c5383575e036484159390e5/asapi/__init__.py#L1
Has been like that since the initial commit.
| asapi\_signal_handling.py", line 17, in _signal_handler | with anyio.open_signal_receiver(signal.SIGTERM, signal.SIGINT) as signals: | anyio\_backends\_asyncio.py", line 1805, in __enter__ | self._loop.add_signal_handler(sig, self._deliver, sig) | asyncio\events.py", line 574, in add_signal_handler | raise NotImplementedError
That's a very weird place to have that error. What event loop implementation are you using? Can you share your version of Python, anyio and asapi?
Thanks
Yes
from asapi import Injected, serve, bind, validate_injections
Generates the error:
Traceback (most recent call last):
File "...server_asapi.py", line 71, in <module>
from asapi import Injected, serve, bind, validate_injections
ImportError: cannot import name 'validate_injections' from 'asapi' (...asapi\__init__.py)
Also, happens when importing from python interpreter ie.
> python
Python 3.11.4 (tags/v3.11.4:d2340ef, Jun 7 2023, 05:45:37) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import asapi
>>> from asapi import Injected, serve, bind, validate_injections
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'validate_injections' from 'asapi' (...asapi\__init__.py)
Windows 11 Pro 23H2 w/ latest update python 3.11.4 anyio 4.4.0 asapi 0.1.2
Ups I can reproduce! The wheel for asapi 0.1.2
was broken. I haven't really setup proper CI yet. Please try 0.1.3
.
from asapi import Injected, serve, bind, validate_injections
Solved with 0.1.3 :)
But, the add_signal_handler
(or other) remains ie.
Traceback (most recent call last):
...asapi\_signal_handling.py", line 48, in handle_signals
yield stop
...asapi\_serve.py", line 21, in serve
await stop.wait()
...anyio\_backends\_asyncio.py", line 1662, in wait
await self._event.wait()
...asyncio\locks.py", line 213, in wait
await fut
asyncio.exceptions.CancelledError: Cancelled by cancel scope 1ea4b2b9890
During handling of the above exception, another exception occurred:
+ Exception Group Traceback (most recent call last):
| ...server_asapi.py", line 585, in <module>
| anyio.run(main)
| ...anyio\_core\_eventloop.py", line 74, in run
| return async_backend.run(func, args, {}, backend_options)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ...anyio\_backends\_asyncio.py", line 2034, in run
| return runner.run(wrapper())
| ^^^^^^^^^^^^^^^^^^^^^
| ...asyncio\runners.py", line 118, in run
| return self._loop.run_until_complete(task)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ...asyncio\base_events.py", line 653, in run_until_complete
| return future.result()
| ^^^^^^^^^^^^^^^
| ...anyio\_backends\_asyncio.py", line 2022, in wrapper
| return await func(*args)
| ^^^^^^^^^^^^^^^^^
| ...server_asapi.py", line 581, in main
| await serve(app, 8000)
| ...asapi\_serve.py", line 18, in serve
| async with handle_signals() as stop:
| ...contextlib.py", line 222, in __aexit__
| await self.gen.athrow(typ, value, traceback)
| ...asapi\_signal_handling.py", line 46, in handle_signals
| async with anyio.create_task_group() as tg:
| ...anyio\_backends\_asyncio.py", line 680, in __aexit__
| raise BaseExceptionGroup(
| ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
+-+---------------- 1 ----------------
| Traceback (most recent call last):
| ...asapi\_signal_handling.py", line 19, in _signal_handler
| with anyio.open_signal_receiver(signal.SIGTERM, signal.SIGINT) as signals:
| ...anyio\_backends\_asyncio.py", line 1805, in __enter__
| self._loop.add_signal_handler(sig, self._deliver, sig)
| ...asyncio\events.py", line 574, in add_signal_handler
| raise NotImplementedError
| NotImplementedError
+------------------------------------
I feel like you might be hitting https://github.com/python/cpython/blob/1b0e63c81b54a937b089fe335761cba4a96c8cdf/Lib/asyncio/events.py#L578, which doesn't make much sense. I'll look deeper tomorrow hopefully.
Thanks. In your time.
Fyi I'm testing asapi with my full system which works using the fastapi Annotated() dependency except for the cli problem which is related to uvicorn. Happy to be a guinea pig for asapi :)
I now set up CI including Windows and added a test that passes.
I'm guessing you're hitting this line? https://github.com/python/cpython/blob/1b0e63c81b54a937b089fe335761cba4a96c8cdf/Lib/asyncio/events.py#L578 Could you share a couple lines above 574 and below in asyncio/events.py
to confirm?
Also could you check if this snippet works for you?
import signal
import anyio
async def main() -> None:
with anyio.open_signal_receiver(signal.SIGTERM, signal.SIGINT) as signals:
async for sig in signals:
print(f'Received signal {sig!r}')
anyio.run(main)
Thanks!
asapi 0.1.3
The problem is at this line : https://github.com/python/cpython/blob/1b0e63c81b54a937b089fe335761cba4a96c8cdf/Lib/asyncio/events.py#L578
See the Traceback above https://github.com/adriangb/asapi/issues/2#issuecomment-2171690585
Don't understand what 'Could you share a couple lines above 574 and below in asyncio/events.py to confirm?' means?
The above snippet generated the Traceback:
Traceback (most recent call last):
...snippet.py", line 11, in <module>
anyio.run(main)
...anyio\_core\_eventloop.py", line 74, in run
return async_backend.run(func, args, {}, backend_options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...anyio\_backends\_asyncio.py", line 2034, in run
return runner.run(wrapper())
^^^^^^^^^^^^^^^^^^^^^
...asyncio\runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...asyncio\base_events.py", line 653, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
...anyio\_backends\_asyncio.py", line 2022, in wrapper
return await func(*args)
^^^^^^^^^^^^^^^^^
...snippet.py", line 6, in main
with anyio.open_signal_receiver(signal.SIGTERM, signal.SIGINT) as signals:
...anyio\_backends\_asyncio.py", line 1805, in __enter__
self._loop.add_signal_handler(sig, self._deliver, sig)
...asyncio\events.py", line 574, in add_signal_handler
raise NotImplementedError
NotImplementedError
I just wanted to confirm what line that error is coming from. Can you let me know what happens with the snippet in https://github.com/adriangb/asapi/issues/2#issuecomment-2181634297?
The snippet:
import signal
import anyio
async def main() -> None:
with anyio.open_signal_receiver(signal.SIGTERM, signal.SIGINT) as signals:
async for sig in signals:
print(f'Received signal {sig!r}')
anyio.run(main)
Generates the Traceback:
Traceback (most recent call last):
...snippet.py", line 11, in <module>
anyio.run(main)
...anyio\_core\_eventloop.py", line 74, in run
return async_backend.run(func, args, {}, backend_options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...anyio\_backends\_asyncio.py", line 2034, in run
return runner.run(wrapper())
^^^^^^^^^^^^^^^^^^^^^
...asyncio\runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...asyncio\base_events.py", line 653, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
...anyio\_backends\_asyncio.py", line 2022, in wrapper
return await func(*args)
^^^^^^^^^^^^^^^^^
...snippet.py", line 6, in main
with anyio.open_signal_receiver(signal.SIGTERM, signal.SIGINT) as signals:
...anyio\_backends\_asyncio.py", line 1805, in __enter__
self._loop.add_signal_handler(sig, self._deliver, sig)
...asyncio\events.py", line 574, in add_signal_handler
raise NotImplementedError
NotImplementedError
I think it may be that (some?) flavors of Windows don't support SIGTERM. Can you try removing SIGTERM?
Thank you for helping me debug, I don't have a Windows machine so I can't really test these things.
Happy to help :)
Removing SIGTERM ie.
import signal
import anyio
async def main() -> None:
with anyio.open_signal_receiver(signal.SIGINT) as signals:
async for sig in signals:
print(f'Received signal {sig!r}')
anyio.run(main)
Generates the Traceback:
Traceback (most recent call last):
...snippet.py", line 9, in <module>
anyio.run(main)
...anyio\_core\_eventloop.py", line 74, in run
return async_backend.run(func, args, {}, backend_options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...anyio\_backends\_asyncio.py", line 2034, in run
return runner.run(wrapper())
^^^^^^^^^^^^^^^^^^^^^
...asyncio\runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...asyncio\base_events.py", line 653, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
...anyio\_backends\_asyncio.py", line 2022, in wrapper
return await func(*args)
^^^^^^^^^^^^^^^^^
...snippet.py", line 5, in main
with anyio.open_signal_receiver(signal.SIGINT) as signals:
...anyio\_backends\_asyncio.py", line 1805, in __enter__
self._loop.add_signal_handler(sig, self._deliver, sig)
...asyncio\events.py", line 574, in add_signal_handler
raise NotImplementedError
NotImplementedError
At the anyio
open_signal_receiver
function https://github.com/agronholm/anyio/blob/e93d5c9157ad045f1f9dffbcbba6d005febdb9e9/src/anyio/_core/_signals.py#L10
it says:
warning:: Windows does not support signals natively so it is best to avoid
relying on this in cross-platform applications.
Maybe setting the asyncio WindowsSelectorEventLoopPolicy is an option to try: https://docs.python.org/3.11/library/asyncio-policy.html#asyncio.WindowsSelectorEventLoopPolicy for Windows ('win*')
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
I’ll probably have to look at what Uvicorn does on Windows and just copy that.
On Sat, Jun 22, 2024 at 1:13 PM Henry Thornton @.***> wrote:
At the anyio open_signal_receiver function https://github.com/agronholm/anyio/blob/e93d5c9157ad045f1f9dffbcbba6d005febdb9e9/src/anyio/_core/_signals.py#L10 it says:
warning:: Windows does not support signals natively so it is best to avoid relying on this in cross-platform applications.
Maybe setting the asyncio WindowsSelectorEventLoopPolicy is an option to try: https://docs.python.org/3.11/library/asyncio-policy.html#asyncio.WindowsSelectorEventLoopPolicy for Windows ('win*')
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
— Reply to this email directly, view it on GitHub https://github.com/adriangb/asapi/issues/2#issuecomment-2184136418, or unsubscribe https://github.com/notifications/unsubscribe-auth/AANMPP72P32BOUBRG6K66G3ZIW5FLAVCNFSM6AAAAABJISYRJKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOBUGEZTMNBRHA . You are receiving this because you commented.Message ID: @.***>
Saw this on the uvicorn site: https://github.com/encode/uvicorn/blob/d79f285184404694c77f7ca649858e7488270cf7/uvicorn/loops/asyncio.py
Hi Wondering if you've had a chance to work on this? Thanks
The code looks like:
The code excecutes
do_startup_stuff()
successfully but fails to start the fastapi app. The error trace is:The full traceback is longer and can post if required.