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

streamSSE() throws an error on close #1918

Closed
hond-hexagon opened this issue Jan 8, 2024 · 3 comments
Closed

streamSSE() throws an error on close #1918

hond-hexagon opened this issue Jan 8, 2024 · 3 comments
Labels

Comments

@hond-hexagon
Copy link

hond-hexagon commented Jan 8, 2024

What version of Hono are you using?

3.12.0

What runtime/platform is your app running on?

Cloudflare Workers

What steps can reproduce the bug?

I have this piece of code:

let sseId = 0;

app.get('/stream-sse', async (c) => {
  return streamSSE(c, async (stream) => {
    for (let i = 0; i < 5; i++) {
      await new Promise((resolve) => setTimeout(resolve, 200));

      const jsonValue = JSON.stringify({ progress: i });
      await stream.writeSSE({ data: jsonValue, id: String(sseId++) });
    }

    console.log('finished?');
  });
});

Once the loop is over and the Response should close, it throws an error of an uncaught exception which over time throws much severe error in the Cloudflare worker.

I tried to replicate an SSE stream with a plain Worker and everything works as expected:

let nonce = 0;

export default {
  async fetch(): Promise<Response> {
    const encoder = new TextEncoder();

    const readableStream = new ReadableStream({
      async pull(controller) {
        for (let i = 0; i < 5; i++) {
          await new Promise((resolve) => setTimeout(resolve, 200));

          const jsonValue = JSON.stringify({ progress: i });
          const sseValue = [`data: ${jsonValue}`, `id: ${nonce++}`].join('\n') + '\n\n';
          const encodedValue = encoder.encode(sseValue);
          controller.enqueue(encodedValue);
        }

        controller.close();
      },
    });

    return new Response(readableStream, {
      headers: {
        'Transfer-Encoding': 'chunked',
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        Connection: 'keep-alive',
      },
    });
  },
};

After digging into hono source code, it seems that flipping preventClose to false in stream.ts solves the issue, a response is closed and there is no uncaught exception. However, I'm not sure what implication this change could have.

What is the expected behavior?

Response should properly close once streamSSE() callback is finished.

What do you see instead?

[wrangler:inf] GET /stream-sse 200 OK (22ms)
✘ [ERROR] A hanging Promise was canceled. This happens when the worker runtime is waiting for a Promise from JavaScript to resolve, but has detected that [object Object]

✘ [ERROR] Uncaught (in response) Error: The script will never generate a response.

Additional information

It behaves the same with locally running wrangler or deployed to Cloudflare.

@hond-hexagon
Copy link
Author

It might be related to #1902 but this issue originates from a server not from a client.

@hond-hexagon hond-hexagon changed the title streamSSE() throw an error on close streamSSE() throws an error on close Jan 8, 2024
@yusukebe
Copy link
Member

yusukebe commented Jan 9, 2024

Hi @hond-hexagon

Thanks for raising the issue.

@sor4chi or @watany-dev Could you see this issue?

@yusukebe
Copy link
Member

yusukebe commented Jun 6, 2024

This has been closed by #2529 . Thanks!

@yusukebe yusukebe closed this as completed Jun 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants