#Immediate ServerSentEvent response with blocking generator

1 messages · Page 1 of 1 (latest)

lilac stump
#

Hi,
I’m implementing an endpoint to open a notification stream using ServerSentEvent replies. I use an asynchronous generator that is waiting a trigger (in my case a publish on a channel).
I m wondering if I could be able to send an immediate HTTP 200 OK reply even if I’m waiting ?

async def notification_publisher(self, channels: ChannelsPlugin) -> AsyncGenerator[SSEData, None]:
        subscriber = await channels.subscribe(["general"])
        async for message in subscriber.iter_events():
            yield message

@get("/{dynamic_id:uuid}/events", status_code=HTTP_200_OK)
    async def subscribe_to_notifications(self, dynamic_id: UUID, channels: ChannelsPlugin) -> ServerSentEvent:
        return ServerSentEvent(self.notification_publisher(channels))

In other words, is it possible to generate a response before the first yield is reached ?
Possible to decorrelate the reply to the GET request and the notifications sending ?

Thank you
Florian

lofty fogBOT
#
Notes for Immediate ServerSentEvent response with blocking generator
At your assistance

@lilac stump

No Response?

If no response in a reasonable time, ping @Member.

Closing

To close, type !solve or byte solve.

MCVE

Please include an MCVE so that we can reproduce your issue locally.

reef ocean
#

No, it's not

#

You can either send a regular response or stream

#

You can't do both

#

(not a litestar thing, that's an HTTP thing 🙂)

#

Can you explain what you're trying to achieve?

#

I'm sure there's some way to handle this

lilac stump
#

What I explain below comes from a “system specification” that is not written by REST API nor HTTP specialist.

I have a client that send a GET request to a specific endpoint to open a notification stream in order to “allow” the server to push notifications.
Specs requires that the servers replies with an HTTP 200 with no content.
Then, on specific event, server will push notifications on the stream.

#

It seems that the standard authorizes it

neat blaze
#

I m wondering if I could be able to send an immediate HTTP 200 OK reply even if I’m waiting ?
isnt this what happens by default?

lilac stump
#

Seems the case in your example, not what I get when I test on my side.

Could you test with something close to my code ?

lilac stump
#

@neat blaze could you share the code of your endpoint

reef ocean
reef ocean
#

If it's receiving the event stream, it should also have received the initial response

lilac stump
hushed lava
#

post a mvce so we can talk

neat blaze
lilac stump
#

@hushed lava

import json
from collections.abc import AsyncGenerator
from litestar import Litestar, Controller, get, post
from litestar.channels import ChannelsPlugin
from litestar.channels.backends.memory import MemoryChannelsBackend
from litestar.response import ServerSentEvent
from litestar.status_codes import HTTP_200_OK, HTTP_204_NO_CONTENT
from litestar.types import SSEData

class NotificationController(Controller):
    path = "/notifications"

    @post("/{dynamic_id:int}", status_code=HTTP_204_NO_CONTENT)
    async def publish_notif(self, dynamic_id: int, channels: ChannelsPlugin) -> None:
 
        channels.publish(json.dumps({"test_key": "value"}), "general")

    async def notification_publisher(self, channels: ChannelsPlugin) -> AsyncGenerator[SSEData, None]:
        subscriber = await channels.subscribe(["general"])
        async for message in subscriber.iter_events():
            yield message

    @get("/{dynamic_id:int}/events", status_code=HTTP_200_OK)
    async def subscribe_to_notifications(self, dynamic_id: int, channels: ChannelsPlugin) -> ServerSentEvent:
        """
        """
        return ServerSentEvent(self.notification_publisher(channels))


channels_plugin = ChannelsPlugin(
    backend=MemoryChannelsBackend(),
    channels=["general"],
    arbitrary_channels_allowed=True
)

app = Litestar(
    path="/api",
    route_handlers=[NotificationController],
    plugins=[channels_plugin]
)
hushed lava
#

i changed nothing in your code, seems to work

lilac stump
#

Yeah it works. The issue is that to get a HTTP 200 Ok response, I need to wait for a publish, that’s not what I want. I want to get a response immediately when the SSE generator is started.

hushed lava
#

i can have a 200 without the need to publish, its working fine

#

what version of litestar you use

#

what trace you got

#

logs

lilac stump
#

Litestar 2.14

#

Serving by granian

#

It seems to work indeed with a browser but don’t get the same output with postman. Could you try ?

hushed lava
#

Ok so it seems like a postman issue

#

I don't use that