dapr / dotnet-sdk

Dapr SDK for .NET
Apache License 2.0
1.12k stars 340 forks source link

Unable to stream using HTTP service invocation #1271

Open afink-osi opened 7 months ago

afink-osi commented 7 months ago

I am attempting to configure and setup HTTP streaming via service to service communication. We have ServiceA which calls a streaming HTTP endpoint on ServiceB through dapr. We are using dapr 1.13 so our understanding is that streaming should be enabled by default.

Following the example from InvokeServiceHttpClientExample.cs we are attempting to use dapr HTTP client to call the streaming endpoint on ServiceB. To keep things simple, we have setup a dummy TestPing route on ServiceB which should stream back 10 items at 500ms intervals.

Minimal Code Sample of ServiceA

var client = DaprClient.CreateInvokeHttpClient(GetDaprAppId());
var sw = Stopwatch.StartNew();

var responseStream = await client.GetStreamAsync(GetPingUriFixed());

var items = JsonSerializer.DeserializeAsyncEnumerable<string>(responseStream, new JsonSerializerOptions { DefaultBufferSize = ItemSize / 2 });
if (sw.ElapsedMilliseconds > Delay * ItemCount)
    throw new InvalidOperationException($"Initial request to took {sw.ElapsedMilliseconds} which is greater than (delay * itemCount) {Delay * ItemCount} which indicates streaming was unsuccessful");

Minimal Code Sample of ServiceB endpoint:

public IActionResult PingStreamFixed()
{
    var delay = 500;
    var itemCount = 10;
    var itemSize = 10 * 1024;

    return Ok(GetResult());

    async IAsyncEnumerable<string> GetResult()
    {
        for (var i = 0; i < itemCount; i++)
        {
            await Task.Delay(delay);
            var item = new byte[itemSize];
            Random.Shared.NextBytes(item);
            yield return Convert.ToBase64String(item);
        }
    }
}

When running this code we find that the response takes 5 seconds to return OK (500ms delay * 10 itemCount) which indicates that streaming is not occurring.

To troubleshoot, we added portforwards on ServiceB as well as ServiceB's dapr sidecar and called the streaming endpoint from a browser to confirm that our test endpoint streams as expected.

When calling the ServiceB streaming endpoint via the browser, we successfully see an initial response, then stream the remaining items in 500ms intervals which is our expected behavior. Request: http://localhost:8080/cluster/test/pingStreamFixed image

However, when we call the endpoint through ServiceB's dapr sidecar, we see that we only get a single, non-streamed response after a full 5 seconds. Request: http://localhost:3500/v1.0/invoke/ep--00000000-0000-0000-0000-000000000000/method/cluster/test/pingStreamFixed image

Question:

It seems our test streaming endpoint behaves as expected and streams when calling our service directly, but not through the dapr sidecar. We have been unable to find any additional examples or documentation to help us get this to work. Is there some sidecar configuration or setting on the daprClient that we are missing to get streaming to work correctly?

philliphoff commented 7 months ago

CC @ItalyPaleAle