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

Fix: SSE Watcher should now close properly across multiple reloads #1748

Merged
merged 1 commit into from
Nov 30, 2022
Merged

Fix: SSE Watcher should now close properly across multiple reloads #1748

merged 1 commit into from
Nov 30, 2022

Conversation

mdwagner
Copy link
Contributor

@mdwagner mdwagner commented Oct 5, 2022

Purpose

Fixes #1744

Description

Instead of updating a flag to reload SSE Watchers, it stores each Request Context into a list and pops off each one when needing to reload.

Checklist

  • - An issue already exists detailing the issue/or feature request that this PR fixes
  • - All specs are formatted with crystal tool format spec src
  • - Inline documentation has been added and/or updated
  • - Lucky builds on docker with ./script/setup
  • - All builds and specs pass on docker with ./script/test

Copy link
Contributor

@robacarp robacarp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. This looks like it should fix the issues I highlighted in #1744:

  • runaway collection of looping sse requests
  • terminated connection errors
  • pre-emptive reload on browsers which are the first to arrive after a hard boot and then recompile

I'll check it out later today.

@robacarp
Copy link
Contributor

robacarp commented Oct 5, 2022

This seems like a good clean up. Thanks @mdwagner.

The connection pool still grows with each page load but it is cleaned up after a reload event. When navigating around, browsers don't send anything back to the server to notify that the connection is being terminated.

This was the case before, but what I'm seeing here is that about 50% of the time my browser reloads before the server is actually ready to accept requests, which results in a connection error. The cheap and easy solution to this is a sleep of a few hundred millis. The complete solution is probably something more complicated.

@robacarp
Copy link
Contributor

robacarp commented Oct 6, 2022

I just ran across this stack trace:

web     | Unhandled exception in spawn: Error while flushing data to the client (HTTP::Server::ClientError)
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/http/server/response.cr:299:9 in 'unbuffered_flush'
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/io/buffered.cr:240:5 in 'flush'
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/http/server/response.cr:118:7 in 'flush'
web     |   from lib/lucky/tasks/watch.cr:91:9 in 'reload'
web     |   from lib/lucky/tasks/watch.cr:235:7 in 'reload_watcher'
web     |   from lib/lucky/tasks/watch.cr:197:9 in 'reload_or_start_watcher'
web     |   from lib/lucky/tasks/watch.cr:183:9 in 'create_app_processes'
web     |   from lib/lucky/tasks/watch.cr:266:17 in 'start_all_processes'
web     |   from lib/lucky/tasks/watch.cr:170:11 in '->'
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/fiber.cr:146:11 in 'run'
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/fiber.cr:98:34 in '->'
web     | Caused by: Error writing to socket: Broken pipe (IO::Error)
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/io/evented.cr:82:13 in 'unbuffered_write'
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/io/buffered.cr:239:5 in 'flush'
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/http/server/response.cr:296:9 in 'unbuffered_flush'
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/io/buffered.cr:240:5 in 'flush'
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/http/server/response.cr:118:7 in 'flush'
web     |   from lib/lucky/tasks/watch.cr:91:9 in 'reload'
web     |   from lib/lucky/tasks/watch.cr:235:7 in 'reload_watcher'
web     |   from lib/lucky/tasks/watch.cr:197:9 in 'reload_or_start_watcher'
web     |   from lib/lucky/tasks/watch.cr:183:9 in 'create_app_processes'
web     |   from lib/lucky/tasks/watch.cr:266:17 in 'start_all_processes'
web     |   from lib/lucky/tasks/watch.cr:170:11 in '->'
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/fiber.cr:146:11 in 'run'
web     |   from /Users/user/.asdf/installs/crystal/1.5.1/src/fiber.cr:98:34 in '->'

@mdwagner
Copy link
Contributor Author

mdwagner commented Oct 8, 2022

I don't think there's much we can about the Broken Pipe error, unless we just swallow the error from the output.

From what I can gather, it's not really an error, more like an informational message about the connection being closed before we can write to it. The same thing can happen on a normal HTTP API request.

@mdwagner
Copy link
Contributor Author

mdwagner commented Oct 8, 2022

This seems like a good clean up. Thanks @mdwagner.

The connection pool still grows with each page load but it is cleaned up after a reload event. When navigating around, browsers don't send anything back to the server to notify that the connection is being terminated.

This was the case before, but what I'm seeing here is that about 50% of the time my browser reloads before the server is actually ready to accept requests, which results in a connection error. The cheap and easy solution to this is a sleep of a few hundred millis. The complete solution is probably something more complicated.

So, the only thing I can think of that we could try, is by setting a reconnection time (retry) on the SSE: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#fields

I'm not sure what else we can do though.

@matthewmcgarvey
Copy link
Member

@mdwagner I'm just checking in on this PR. Do you think this is in a "good enough" state? Just trying not to let this PR get too stale just because it doesn't make everything perfect

@mdwagner
Copy link
Contributor Author

@matthewmcgarvey Yeah, I think it's good enough. If it continues to be a problem in the future, we could just remove SSE support, but for now I think it works.

@matthewmcgarvey
Copy link
Member

Cool, feel free to make the draft ready to review @mdwagner

@mdwagner mdwagner marked this pull request as ready for review November 30, 2022 03:30
Copy link
Member

@jwoertink jwoertink left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix!

@jwoertink jwoertink merged commit 1e101e9 into luckyframework:main Nov 30, 2022
@mdwagner mdwagner deleted the fix/sse-watcher branch December 1, 2022 02:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SSE Watcher issues
4 participants