Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streaming over http seems to be broken in v1.11 #624

Open
thomasl8 opened this issue Jul 29, 2024 · 4 comments
Open

Streaming over http seems to be broken in v1.11 #624

thomasl8 opened this issue Jul 29, 2024 · 4 comments
Assignees
Labels
bug Something isn't working json

Comments

@thomasl8
Copy link

thomasl8 commented Jul 29, 2024

Hello,

We use this library (the circe version) to stream a large JSON payload over HTTP.

It has been working great with version 1.10, however when we upgrade to version 1.11 the server seems to want to collect the entire payload before returning any data to the UI (so basically not streaming). It could be that we are using the library incorrectly for our purposes. If it makes a difference, we are using tapir as our HTTP library.

This is our code (some stuff renamed). Maybe we are doing something wrong? Any help will be much appreciated! Thanks.

          myService
            .getBigFs2Stream
            .through(ast.tokenize)
            .through(wrap.asTopLevelArray)
            .through(render.compact)
            .through(text.utf8.encode)
            .pure[IO]
@satabin
Copy link
Member

satabin commented Jul 29, 2024

Hey, thanks for reporting. This sounds like a real regression indeed. In 1.11.0, we changed the way rendering is done, and I may have introduced this regression.

Can you try to replace the rendering pipe line with

.through(fs2.data.text.render.pretty(0)(fs2.data.json.Token.compact))

And let me know if it fixes it?

@satabin satabin added bug Something isn't working json labels Jul 29, 2024
@satabin satabin self-assigned this Jul 29, 2024
@satabin
Copy link
Member

satabin commented Aug 3, 2024

I am investigating the issue, and added a test (see #627). It looks like the compact pipe emits chunk really early (only singletons for now, even), even if the input is a single big chunk.

Can I see how the resulting stream is used in tapir? Can you confirm that you still get several chunks right after the .through(render.compact)?

@ybasket
Copy link
Collaborator

ybasket commented Aug 3, 2024

I wrote a little test program that tries to come as close as possible to the original report, but without tAPIr:

import cats.effect.*
import fs2.*
import fs2.data.json.*
import io.circe.Json

import scala.concurrent.duration.*

object EndlessMain extends IOApp.Simple {

  override def run: IO[Unit] =
    countingJson
      .meteredStartImmediately(0.001.seconds)
      .through(ast.tokenize)
      .through(wrap.asTopLevelArray)
      .through(render.compact)
      // .through(text.utf8.encode)
      .evalMap(IO.println(_))
      .compile
      .drain

  def countingJson: Stream[IO, Json] =
    Stream.iterate(0)(_ + 1).map(Json.fromInt)
}

When run, it outputs immediately, like this:

[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8

And as the Stream is infinite by construction, it's guaranteed nothing is fully loaded into memory before output. So as @satabin pointed out, it seems worth looking into the tAPIr integration and ensure chunking is preserved.

@satabin
Copy link
Member

satabin commented Sep 7, 2024

Hi @thomasl8, did you have a chance to look into this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working json
Projects
None yet
Development

No branches or pull requests

3 participants