litestar-org/litestar

Bug: Custom plugin with lifespan breaks channel startup hook

TheZwieback opened this issue · 1 comments

Description

I wrote a simple plugin with a lifespan based on a context manager. When I add the custom plugin and the channels plugin, the channels plugin does not initialize properly. If I remove the lifespan from the custom plugin it works.

URL to code causing the issue

No response

MCVE

from litestar import Litestar, post
from litestar.testing import TestClient
from litestar.channels import ChannelsPlugin
from litestar.channels.backends.memory import MemoryChannelsBackend
from litestar.channels import ChannelsPlugin
from litestar.plugins import InitPluginProtocol
from contextlib import asynccontextmanager
from collections.abc import AsyncGenerator
import logging


@post("/publish_something")
async def handler(channels: ChannelsPlugin) -> None:
    channels.publish("test", "my_new_channel")


@asynccontextmanager
async def some_lifecycle(app: "Litestar") -> "AsyncGenerator[None, None]":
    logging.info("some startup")
    try:
        yield
    finally:
        logging.info("some shutdown")


class SomePlugin(InitPluginProtocol):
    def on_app_init(self, app_config: "AppConfig") -> "AppConfig":
        # comment this out and the startup works
        app_config.lifespan = [some_lifecycle]
        return app_config


with TestClient(
    app=Litestar(
        debug=True,
        plugins=[
            ChannelsPlugin(backend=MemoryChannelsBackend(history=0), channels=[], arbitrary_channels_allowed=True),
            SomePlugin(),
        ],
        route_handlers=[handler],
    )
) as client:
    client.post("/publish_something")

Steps to reproduce

1. Run the script
2. It errors out when hitting the publish_something route

Screenshots

"![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)"

Logs

INFO - 2024-06-26 12:15:33,244 - root - bug - some startup
ERROR - 2024-06-26 12:15:33,255 - litestar - config - Uncaught exception (connection_type=http, path=/publish_something):
Traceback (most recent call last):
  File "/root/innovation-framework/.venv/lib/python3.12/site-packages/litestar/channels/plugin.py", line 144, in publish
    self._pub_queue.put_nowait((data, list(channels)))  # type: ignore[union-attr]
    ^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'put_nowait'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/root/innovation-framework/.venv/lib/python3.12/site-packages/litestar/middleware/_internal/exceptions/middleware.py", line 159, in __call__
    await self.app(scope, receive, capture_response_started)
  File "/root/innovation-framework/.venv/lib/python3.12/site-packages/litestar/_asgi/asgi_router.py", line 99, in __call__
    await asgi_app(scope, receive, send)
  File "/root/innovation-framework/.venv/lib/python3.12/site-packages/litestar/routes/http.py", line 80, in handle
    response = await self._get_response_for_request(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/innovation-framework/.venv/lib/python3.12/site-packages/litestar/routes/http.py", line 132, in _get_response_for_request
    return await self._call_handler_function(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/innovation-framework/.venv/lib/python3.12/site-packages/litestar/routes/http.py", line 152, in _call_handler_function
    response_data, cleanup_group = await self._get_response_data(
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/innovation-framework/.venv/lib/python3.12/site-packages/litestar/routes/http.py", line 200, in _get_response_data
    else await route_handler.fn(**parsed_kwargs)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/innovation-framework/bug.py", line 14, in handler
    channels.publish("test", "my_new_channel")
  File "/root/innovation-framework/.venv/lib/python3.12/site-packages/litestar/channels/plugin.py", line 146, in publish
    raise RuntimeError("Plugin not yet initialized. Did you forget to call on_startup?") from e
RuntimeError: Plugin not yet initialized. Did you forget to call on_startup?
INFO - 2024-06-26 12:15:33,264 - httpx - _client - HTTP Request: POST http://testserver.local/publish_something "HTTP/1.1 500 Internal Server Error"
INFO - 2024-06-26 12:15:33,266 - root - bug - some shutdown

Litestar Version

2.9.1

Platform

  • Linux
  • Mac
  • Windows
  • Other (Please specify in the description above)

Note

While we are open for sponsoring on GitHub Sponsors and
OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.

Check out all issues funded or available for funding on our Polar.sh dashboard

  • If you would like to see an issue prioritized, make a pledge towards it!
  • We receive the pledge once the issue is completed & verified
  • This, along with engagement in the community, helps us know which features are a priority to our users.
Fund with Polar

Sorry, I figured it out:
app_config.lifespan = [some_lifecycle]
should be
app_config.lifespan += [some_lifecycle]