Ocelot icon indicating copy to clipboard operation
Ocelot copied to clipboard

Server-sent events protocol

Open dingfengwu opened this issue 6 years ago • 18 comments

Documentation

Search

dingfengwu avatar Jun 24 '19 07:06 dingfengwu

Maybe we could add here some more information: SSE (Server-Sent Events) isn't working for me

trickreich avatar Sep 10 '19 13:09 trickreich

I've faced with same problem. Our .NET Core backend sits behind API Gateway (Ocelot) and I've added SignalR hub recently. We only need one-way communication from backend to SPA (front-end app). Server-Sent Event (SSE) transport is one of three options SignalR provides and it looks like a perfect lightweight candiate. Client app works flawlesly when it is connected direcetly to the backend (which is IIS hosted), but when accessing via API Gateway the Ocelot stucks.

First request (the handshake) passes fine:

HTTP POST /myservice/hubs/notifications/negotiate HTTP/1.1

HTTP/1.1 200 OK
Content-Length: 125
Content-Type: application/json
Server: Kestrel
Date: Fri, 01 Nov 2019 12:49:48 GMT

{"connectionId":"IepBcjkYfdnXxg3Vn-z24Q","availableTransports":[{"transport":"ServerSentEvents","transferFormats":["Text"]}]}

However the second connection which should be a long-living text/event-stream connection fails after few seconds:

GET /myservice/hubs/notifications?id=IepBcjkYfdnXxg3Vn-z24Q HTTP/1.1

HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Length: 49
Content-Type: text/event-stream
Server: Kestrel
Date: Fri, 01 Nov 2019 12:50:03 GMT

:
data: {"error":"Handshake was canceled."}

The Ocelot outputs this into console log:

18:14:29:637 Debug: Ocelot.Requester.Middleware.HttpRequesterMiddleware requestId: 0HLQUQ3CANMQU:00000002, previousRequestId: no previous request id, message: setting http response message
18:14:29:642 Debug: Ocelot.Responder.Middleware.ResponderMiddleware requestId: 0HLQUQ3CANMQU:00000002, previousRequestId: no previous request id, message: no pipeline errors, setting and returning completed response
18:14:29:644 Debug: Ocelot.Errors.Middleware.ExceptionHandlerMiddleware requestId: 0HLQUQ3CANMQU:00000002, previousRequestId: no previous request id, message: ocelot pipeline finished

After short investigation it appears that pipeline was not designed to pass-though streamed responses:

HttpRequesterMiddleware simply reads the whole response:

var response = await _requester.GetResponse(context);
...
context.DownstreamResponse = new DownstreamResponse(response.Data);
await _next.Invoke(context);

The requested uses standard HttpClient to read the response.

However, I see that Ocelot has special (dedicated) pipeline to handle websocket connections:

            // If the request is for websockets upgrade we fork into a different pipeline
            builder.MapWhen(context => context.HttpContext.WebSockets.IsWebSocketRequest,
                app =>
                {
                    app.UseDownstreamRouteFinderMiddleware();
                    app.UseDownstreamRequestInitialiser();
                    app.UseLoadBalancingMiddleware();
                    app.UseDownstreamUrlCreatorMiddleware();
                    app.UseWebSocketsProxyMiddleware();
                });

The WebSocketsProxyMiddleware middleware contains an infinite loop that pumps the data in both directions:

var destinationUri = new Uri(serverEndpoint);
            await client.ConnectAsync(destinationUri, context.RequestAborted);
            using (var server = await context.WebSockets.AcceptWebSocketAsync(client.SubProtocol))
            {
                var bufferSize = DefaultWebSocketBufferSize;
                await Task.WhenAll(PumpWebSocket(client, server, bufferSize, context.RequestAborted), PumpWebSocket(server, client, bufferSize, context.RequestAborted));
            }

The HttpRequesterMiddleware does not make any attempts to pump streamable content (say if HTTP Content-Type is text/event-stream).

Can we please have either alternative pipeline for SSE or, may be, some adjustments in HttpRequesterMiddleware that will make pumping SSE traffic possible?

I would appreciate if @TomPallister comment on this :)

snb83 avatar Nov 01 '19 14:11 snb83

@snb83 That means it's not working for you, right?

trickreich avatar Dec 11 '19 09:12 trickreich

@snb83 That means it's not working for you, right?

Yes, SSE transport does not work for me when notifications are routed via Ocelot API Gateway.

snb83 avatar Dec 11 '19 11:12 snb83

Hi, ¿there are some update about that?

luheorga avatar Jul 09 '20 15:07 luheorga

Hi, any update on this?

ganhj99 avatar Oct 06 '22 04:10 ganhj99

Hello any update on this? I am also facing the same issue.

coppercarpenter avatar Mar 31 '23 18:03 coppercarpenter

Interested on looking how this goes too. 👀

byjokese avatar Nov 24 '23 17:11 byjokese

Watching this issue for the updates. I faced the same challenge today and had to spend several late night hours before concluding...

krishnankuppaswamy avatar Nov 30 '23 11:11 krishnankuppaswamy

@krishnankuppaswamy @byjokese @coppercarpenter @ganhj99 @luheorga @trickreich Hello guys!

@dingfengwu And, dear author,

Welcome to Ocelot to contribute! As a team, we are open to discuss, review PRs... If someone has an intention to contribute, then Welcome!

raman-m avatar Nov 30 '23 12:11 raman-m

@snb83 commented on Nov 1, 2019

Hi Sergei! Right, we have different pipelines for Http & Websoket traffic.

Can we please have either alternative pipeline for SSE or, may be, some adjustments in HttpRequesterMiddleware that will make pumping SSE traffic possible?

Yes, we can. But, will you contribute actively? Seems we have to design & develop 3rd pipeline for SSE protocol... I'm not sure we can reuse Http pipeline somehow... I can reopen this issue, if you're still with Ocelot... 😉

raman-m avatar Nov 30 '23 12:11 raman-m

keeping some notes for the feature: HttpContext.Features.Get<IHttpResponseBodyFeature>().DisableBuffering() https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.features.ihttpresponsebodyfeature?view=aspnetcore-8.0 @ggnaegi @raman-m

it's related to this discussion: https://github.com/ThreeMammals/Ocelot/discussions/1943

ggnaegi avatar Jan 23 '24 16:01 ggnaegi

add config in public void Configure(IApplicationBuilder app, IWebHostEnvironment env), not using middleware

app.Use(async (context, next) => {
    context.Request.EnableBuffering();
    await next();
});

Ocelot setting json:

{
  "DownstreamPathTemplate": "/notice/{eveything}",
  "DownstreamScheme": "https",
  "DownstreamHostAndPorts": [
    {
      "Host": "localhost",
      "Port": 9000
    }
  ],
  "UpstreamPathTemplate": "/notice/{eveything}",
  "UpstreamHttpMethod": [ "POST", "PUT", "GET", "DELETE", "PATCH" ],
  "DangerousAcceptAnyServerCertificateValidator": true
},
Screenshot 2024-07-21 103343

truongnguyengithub avatar Jul 21 '24 03:07 truongnguyengithub

Hello @truongnguyengithub! What were you trying to communicate or demonstrate? Were you suggesting that the Server-sent events protocol functions effectively with context.Request.EnableBuffering() without the need for .DisableBuffering()?

I would mention that in certain applications and user environments, both methods might be viable, although we do not officially support the SSE protocol. There have been no professional pull requests for an Ocelot Core update. However, we acknowledge the widespread popularity of SSE, and as a team, we are prepared to give priority to the development of this protocol to finally enable it in routing schemes.

raman-m avatar Jul 22 '24 17:07 raman-m

Hi @raman-m

I am looking to solve the SSE issue when using Ocelot for my project. It would be great if Ocelot Core was updated with this protocol. I hope to have a release soon.

truongnguyengithub avatar Jul 24 '24 01:07 truongnguyengithub

@truongnguyengithub, are you prepared for a professional contribution? If so, I will reopen the issue once the PR is opened.

raman-m avatar Jul 24 '24 06:07 raman-m

@truongnguyengithub, are you prepared for a professional contribution? If so, I will reopen the issue once the PR is opened.

Hey @raman-m , how are you doing?

I have created a PR for this - https://github.com/ThreeMammals/Ocelot/pull/2300. Could you review it?

vijay-karavadra avatar Jul 13 '25 14:07 vijay-karavadra

Reopened due to the PR https://github.com/ThreeMammals/Ocelot/pull/2300

@vijay-karavadra Thanks for opening the PR! You are now officially assigned to this issue.

And Vijay, remember that designing, developing, and delivering this feature won't be an easy task. Wishing you the best of luck with the development! 😉

raman-m avatar Jul 14 '25 12:07 raman-m