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

"Software rugpull" for multi-worker support #4487

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

evnchn
Copy link
Contributor

@evnchn evnchn commented Mar 17, 2025

we create another client with the same id, and, we let it take over of the socket connection.


#1539 (reply in thread)

Everything just works.

I make a web request to port 8000 using my custom balancer, which remembers I made an HTTP request to which port (say: 8080), and actively refuses to let me talk to such port in the websocket (picking from 8081, 8082, 8083).

This is why it is beneficial to make your own balancer @rodja 😉

Then, on the page load for async pages, it loads up to the part before await ui.context.client.connected()

{C03E4283-95E3-405E-B62B-6FE200076FF1}

Afterwards, the "Software Rugpull" kicks in, and the page is swapped out with what the other process responds with.

{A196E690-F044-4D46-A2C2-B6F2C5235E8F}

For sync pages, the old content also briefly flashes before the new content from the client in the rugpull operation is written to the screen.

{E8DA6F65-5E4A-4B49-84A2-9F6AE1DC1B20}

Afterwards, the interactivity works properly following the new client.

{46ED10AA-AB8D-4379-B03D-84ECE79C04F2}

But, let me also explain how it works. It's fun, really!

When, on handshake, it realizes it just got "cold-called" by a browser whose proclaimed client_id in the data doesn't exist, it:

  • Matches the request by immeidately spawning one such client with a matching client_id
  • Digs through the page route to function dictionary in reverse and calling it
  • Sets up the communication just like it would otherwise
  • Return true so that the browser won't refresh

This is enabled by:

  • making await ui.context.client.connected() do absolutely nothing if the client was spawned in response to a cold call
  • Browser now also passes the path of the page, making it possible to do the reverse lookup in the page route to function dictionary

Honestly it is amazing that it works so well as it stands. I can already forsee some code cleanups.

And also, the args and kwargs of the page are completely neglected as it stands.

@evnchn
Copy link
Contributor Author

evnchn commented Mar 17, 2025

Testing is done via scripts here:

evnchn/nicegui-multiworker-alpha@75523b9

@evnchn
Copy link
Contributor Author

evnchn commented Mar 17, 2025

Oh yeah, forgot to mention:

Since the page actually updates with the new content, you could argue that the page we sent with the HTTP using worker A at port 8080 is indeed the "super tiny, generic html page which establishes a websocket connection" that @falkoschindler wanted in #1539 (comment)

Moreover, since the page is essentially re-evaluated in full by worker B in port 8081, I don't really see any data inconsistency issues where worker B works with missing data which only worker A have access to, as it will re-execute and come to (hopefully) the same conclusion as worker A.

So, this behaviour could be the default behaviour for worker>1, no need allow_worker_switchover=True in the @ui.page

@evnchn evnchn changed the title Software rugpull: we create another client with the same id "Software rugpull" for multi-worker support Mar 17, 2025
@evnchn
Copy link
Contributor Author

evnchn commented Mar 17, 2025

Why it is called a "Software Rugpull":

https://youtu.be/q5M0TwnkWUM?t=3735

I can phrase it in the same language as the Phoenix Hyperspace patent as well!

At this point the behaviour of _on_handshake diverges greatly from the traditional behaviour. For, upon the reception of a non-existent client_id in the handshake, the handler proceeds instead to create a matching client with the correct id and invokes the page function, establishing communication properly to a browser that is none-the-wiser.

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.

1 participant