Skip to content

Commit

Permalink
πŸ¦† Fix #2416 maybe by avoiding race condition (#2501)
Browse files Browse the repository at this point in the history
  • Loading branch information
fonsp authored Apr 5, 2023
1 parent 790ca6d commit 1737e0d
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/evaluation/Run.jl
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ function run_reactive_core!(
cell.running = true
# Important to not use empty! here because AppendonlyMarker requires a new array identity.
# Eventually we could even make AppendonlyArray to enforce this but idk if it's worth it. yadiyadi.
cell.logs = []
cell.logs = Vector{Dict{String,Any}}()
send_notebook_changes_throttled()

if any_interrupted || notebook.wants_to_interrupt || !will_run_code(notebook)
Expand Down
43 changes: 26 additions & 17 deletions src/webserver/Dynamic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -173,31 +173,40 @@ end
For each connected client, we keep a copy of their current state. This way we know exactly which updates to send when the server-side state changes.
"""
const current_state_for_clients = WeakKeyDict{ClientSession,Any}()
const current_state_for_clients_lock = ReentrantLock()

"""
Update the local state of all clients connected to this notebook.
"""
function send_notebook_changes!(πŸ™‹::ClientRequest; commentary::Any=nothing, skip_send::Bool=false)
notebook_dict = notebook_to_js(πŸ™‹.notebook)
for (_, client) in πŸ™‹.session.connected_clients
if client.connected_notebook !== nothing && client.connected_notebook.notebook_id == πŸ™‹.notebook.notebook_id
current_dict = get(current_state_for_clients, client, :empty)
patches = Firebasey.diff(current_dict, notebook_dict)
patches_as_dicts::Array{Dict} = Firebasey._convert(Array{Dict}, patches)
current_state_for_clients[client] = deep_enough_copy(notebook_dict)

# Make sure we do send a confirmation to the client who made the request, even without changes
is_response = πŸ™‹.initiator !== nothing && client == πŸ™‹.initiator.client

if !skip_send && (!isempty(patches) || is_response)
response = Dict(
:patches => patches_as_dicts,
:response => is_response ? commentary : nothing
)
putclientupdates!(client, UpdateMessage(:notebook_diff, response, πŸ™‹.notebook, nothing, πŸ™‹.initiator))
outbox = Set{Tuple{ClientSession,UpdateMessage}}()

lock(current_state_for_clients_lock) do
notebook_dict = notebook_to_js(πŸ™‹.notebook)
for (_, client) in πŸ™‹.session.connected_clients
if client.connected_notebook !== nothing && client.connected_notebook.notebook_id == πŸ™‹.notebook.notebook_id
current_dict = get(current_state_for_clients, client, :empty)
patches = Firebasey.diff(current_dict, notebook_dict)
patches_as_dicts::Array{Dict} = Firebasey._convert(Array{Dict}, patches)
current_state_for_clients[client] = deep_enough_copy(notebook_dict)

# Make sure we do send a confirmation to the client who made the request, even without changes
is_response = πŸ™‹.initiator !== nothing && client == πŸ™‹.initiator.client

if !skip_send && (!isempty(patches) || is_response)
response = Dict(
:patches => patches_as_dicts,
:response => is_response ? commentary : nothing
)
push!(outbox, (client, UpdateMessage(:notebook_diff, response, πŸ™‹.notebook, nothing, πŸ™‹.initiator)))
end
end
end
end

for (client, msg) in outbox
putclientupdates!(client, msg)
end
try_event_call(πŸ™‹.session, FileEditEvent(πŸ™‹.notebook))
end

Expand Down

0 comments on commit 1737e0d

Please sign in to comment.