Fix websocket race condition (#261)

This commit is contained in:
Nikhil Rao 2023-01-14 16:49:45 -08:00 committed by GitHub
parent c8936355f2
commit 1e64e62842
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 23 additions and 10 deletions

View File

@ -1 +1 @@
0.1.12 0.1.13

View File

@ -96,12 +96,13 @@ export const applyEvent = async (event, router, socket) => {
/** /**
* Process an event off the event queue. * Process an event off the event queue.
* @param state The state with the event queue. * @param state The state with the event queue.
* @param setState The function to set the state.
* @param result The current result * @param result The current result
* @param setResult The function to set the result. * @param setResult The function to set the result.
* @param router The router object. * @param router The router object.
* @param socket The socket object to send the event on. * @param socket The socket object to send the event on.
*/ */
export const updateState = async (state, result, setResult, router, socket) => { export const updateState = async (state, setState, result, setResult, router, socket) => {
// If we are already processing an event, or there are no events to process, return. // If we are already processing an event, or there are no events to process, return.
if (result.processing || state.events.length == 0) { if (result.processing || state.events.length == 0) {
return; return;
@ -112,25 +113,34 @@ export const updateState = async (state, result, setResult, router, socket) => {
return; return;
} }
// Process the next event in the queue. // Set processing to true to block other events from being processed.
setResult({ ...result, processing: true }); setResult({ ...result, processing: true });
await applyEvent(state.events.shift(), router, socket);
// Pop the next event off the queue and apply it.
const event = state.events.shift()
// Set new events to avoid reprocessing the same event.
setState({ ...state, events: state.events });
// Apply the event.
await applyEvent(event, router, socket);
}; };
/** /**
* Connect to a websocket and set the handlers. * Connect to a websocket and set the handlers.
* @param socket The socket object to connect. * @param socket The socket object to connect.
* @param state The state object to apply the deltas to. * @param state The state object to apply the deltas to.
* @param setState The function to set the state.
* @param setResult The function to set the result. * @param setResult The function to set the result.
* @param endpoint The endpoint to connect to. * @param endpoint The endpoint to connect to.
*/ */
export const connect = async (socket, state, result, setResult, router, endpoint) => { export const connect = async (socket, state, setState, result, setResult, router, endpoint) => {
// Create the socket. // Create the socket.
socket.current = new WebSocket(endpoint); socket.current = new WebSocket(endpoint);
// Once the socket is open, hydrate the page. // Once the socket is open, hydrate the page.
socket.current.onopen = () => { socket.current.onopen = () => {
updateState(state, result, setResult, router, socket.current) updateState(state, setState, result, setResult, router, socket.current)
} }
// On each received message, apply the delta and set the result. // On each received message, apply the delta and set the result.

View File

@ -162,10 +162,11 @@ READY = f"const {{ isReady }} = {ROUTER};"
USE_EFFECT = join( USE_EFFECT = join(
[ [
"useEffect(() => {{", "useEffect(() => {{",
" if(!isReady)", " if(!isReady) {{",
f" return;", f" return;",
" }}",
f" if (!{SOCKET}.current) {{{{", f" if (!{SOCKET}.current) {{{{",
f" connect({SOCKET}, {{state}}, {RESULT}, {SET_RESULT}, {ROUTER}, {EVENT_ENDPOINT})", f" connect({SOCKET}, {{state}}, {{set_state}}, {RESULT}, {SET_RESULT}, {ROUTER}, {EVENT_ENDPOINT})",
" }}", " }}",
" const update = async () => {{", " const update = async () => {{",
f" if ({RESULT}.{STATE} != null) {{{{", f" if ({RESULT}.{STATE} != null) {{{{",
@ -179,7 +180,7 @@ USE_EFFECT = join(
f" {PROCESSING}: false,", f" {PROCESSING}: false,",
" }})", " }})",
" }}", " }}",
f" await updateState({{state}}, {RESULT}, {SET_RESULT}, {ROUTER}, {SOCKET}.current)", f" await updateState({{state}}, {{set_state}}, {RESULT}, {SET_RESULT}, {ROUTER}, {SOCKET}.current)",
" }}", " }}",
" update()", " update()",
"}})", "}})",

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "pynecone-io" name = "pynecone-io"
version = "0.1.11" version = "0.1.13"
description = "The easiest way to build web apps." description = "The easiest way to build web apps."
license = "Apache-2.0" license = "Apache-2.0"
authors = [ authors = [
@ -53,3 +53,5 @@ pc = "pynecone.pc:main"
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
[tool.pyright]