bridgetownrb / bridgetown

A next-generation progressive site generator & fullstack framework, powered by Ruby
https://www.bridgetownrb.com
MIT License
1.14k stars 114 forks source link

Refactor live reloads to use Rack 3 streaming bodies #861

Closed ayushn21 closed 6 months ago

ayushn21 commented 7 months ago

Summary

As https://github.com/bridgetownrb/bridgetown/issues/860 mentions, we should bump our Rack version to Rack 3. This allows us to use Rack streaming bodies for Server Sent Events.

Motivation

The current code is a bit complex and this is a great opportunity to simplify it.

Reference-level explanation

Rack 3 streaming bodies allows us to keep a socket open and keep writing data to it. We can use this technique in conjunction with a background thread to solidify and simplify this feature.

We're currently tying up a Puma thread for live reload. It's no big deal in dev, but if we offload it to a background thread we won't have to deal with Puma timeouts (hopefully).

Unresolved Questions

Will it work? I've got a POC in place but time will tell. I'll keep using it and report back.

jaredcwhite commented 7 months ago

I'm very excited about this @ayushn21! I remember feeling disappointed that I had to jump through a lot of hoops to get live reload via SSE to work sorta OK without tying up threads and making regular responses hang. With this new Rack 3 streaming approach, does that mean SSE could work on routes generally without sucking up all the Puma threads?

ayushn21 commented 7 months ago

With this new Rack 3 streaming approach, does that mean SSE could work on routes generally without sucking up all the Puma threads?

Yes, that's the general idea. The same approach was possible with Rack 2 as well, just felt a bit hacky. Rack 3 has formally adopted the paradigm of bi-directional communication making something like this a lot easier. I really need to blog about this.

We'll still need to create a Thread of our own to free up the Puma thread, but I've got a few prototypes working so hopefully shouldn't be a massive problem.

In terms of doing this in production, that's probably still a bad idea with Puma. Since we're creating our own thread to free up the Puma thread, we're also responsible for managing it. In dev, that's not an issue since it's just one thread for live reload. In production, where there are multiple connections, it could all get unwieldy very quickly without proper thread management which is difficult at the best of times.

This is where Falcon shines actually because it uses Fibers and is incredible at switching between them. In that case we wouldn't have to worry about creating our own thread or anything, we can just let Falcon take care of everything.