authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-10-03 21:25:41-07:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-10-03 21:43:41-07:00
loge555f7cca8a01b01a44cb5a6689d4e8f7072491a
treef194aacb8e619b9acd6e5c183c79bff3f7be68bf
parent724f7aa7062d2a561f051778a85ee35deb71ebf7
signature Signed by SSH key SHA256:52mNGHRsVFBDED9IAX5pe+LRWUefqTbxEReunq21QvU

docs: clarify sync shutdown in the browser

Native stop waits for in-flight work; browser cancellation lets that work finish while it retains cache ownership. Remove comments that assumed every browser sync step was synchronous. Validation: cargo fmt and notebook doctests. Assisted-by: gpt-6.1-sol

3 files changed, 5 insertions(+), 9 deletions(-)

crates/notebook/src/background.rs+1-3
...@@ -508,13 +508,11 @@ impl Background {...@@ -508,13 +508,11 @@ impl Background {
508 self.0.signal.wake();508 self.0.signal.wake();
509 }509 }
510510
511 /// Stops for good, waiting for the step in flight, so that no replica stays open and no511 /// Stops future checks; native threads finish the current step before returning.
512 /// watch holds the notebook's folder.
513 pub fn stop(&self) {512 pub fn stop(&self) {
514 self.0.signal.stopped.store(true, Ordering::Release);513 self.0.signal.stopped.store(true, Ordering::Release);
515 self.0.signal.wake();514 self.0.signal.wake();
516 let thread = self.1.lock().ok().and_then(|mut thread| thread.take());515 let thread = self.1.lock().ok().and_then(|mut thread| thread.take());
517 // In the browser no step is in flight while another task runs.
518 #[cfg(not(target_arch = "wasm32"))]516 #[cfg(not(target_arch = "wasm32"))]
519 if let Some(thread) = thread {517 if let Some(thread) = thread {
520 let _ = thread.join();518 let _ = thread.join();
crates/notebook/src/session.rs+2-3
...@@ -2390,9 +2390,8 @@ impl Section {...@@ -2390,9 +2390,8 @@ impl Section {
2390 &self.replica2390 &self.replica
2391 }2391 }
23922392
2393 /// Waits for the in-flight operation and callback before releasing the replica.2393 /// Stops future sync steps; native threads finish the current operation before returning.
2394 /// Dropping instead requests cancellation without waiting; the worker retains2394 /// The worker retains cache ownership until its in-flight operation finishes.
2395 /// cache ownership until that operation finishes. Remote calls must be bounded.
2396 pub fn close(mut self) -> Result<()> {2395 pub fn close(mut self) -> Result<()> {
2397 match self.worker.take() {2396 match self.worker.take() {
2398 Some(worker) => worker.stop(),2397 Some(worker) => worker.stop(),
crates/notebook/src/worker.rs+2-3
...@@ -79,7 +79,7 @@ impl Signal {...@@ -79,7 +79,7 @@ impl Signal {
79}79}
8080
81/// Owns automatic reconciliation. Dropping requests cancellation without blocking.81/// Owns automatic reconciliation. Dropping requests cancellation without blocking.
82/// The in-flight sync step finishes before ownership is released; `stop` waits for it.82/// The in-flight sync step retains cache ownership until it finishes.
83pub struct SyncWorker {83pub struct SyncWorker {
84 signal: Arc<Signal>,84 signal: Arc<Signal>,
85 thread: Option<JoinHandle<Result<()>>>,85 thread: Option<JoinHandle<Result<()>>>,
...@@ -116,14 +116,13 @@ impl SyncWorker {...@@ -116,14 +116,13 @@ impl SyncWorker {
116 self.signal.wake();116 self.signal.wake();
117 }117 }
118118
119 /// Cancels future steps and waits for the current step and callback to finish.119 /// Cancels future steps; native threads finish the current step and callback before returning.
120 /// A stopped worker leaves pending edits and uncertain attempts in the cache.120 /// A stopped worker leaves pending edits and uncertain attempts in the cache.
121 /// Call outside the worker's own callback, which cannot join its calling thread.121 /// Call outside the worker's own callback, which cannot join its calling thread.
122 pub fn stop(mut self) -> Result<()> {122 pub fn stop(mut self) -> Result<()> {
123 self.signal.stopped.store(true, Ordering::Release);123 self.signal.stopped.store(true, Ordering::Release);
124 self.signal.wake();124 self.signal.wake();
125 let thread = self.thread.take().expect("Worker owns its thread");125 let thread = self.thread.take().expect("Worker owns its thread");
126 // In the browser no step is in flight outside the worker's own callback.
127 #[cfg(target_arch = "wasm32")]126 #[cfg(target_arch = "wasm32")]
128 return thread.finished().unwrap_or(Ok(()));127 return thread.finished().unwrap_or(Ok(()));
129 #[cfg(not(target_arch = "wasm32"))]128 #[cfg(not(target_arch = "wasm32"))]