Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions crates/daemon/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,24 @@ fn spawn_initial_preload(
WorkspaceCancellation,
tokio::task::JoinHandle<anyhow::Result<WorkspaceStatus>>,
) {
spawn_initial_preload_with_watcher(daemon, published, lifecycle, events, |daemon| {
restart_live_watcher(daemon).map_err(|error| anyhow::anyhow!(error.to_string()))
})
}

pub(super) fn spawn_initial_preload_with_watcher<F>(
daemon: Arc<Mutex<WorkspaceDaemon>>,
published: Arc<RwLock<Option<PublishedSnapshot>>>,
lifecycle: Arc<RwLock<WorkspaceLifecycle>>,
events: tokio::sync::broadcast::Sender<WorkspaceEventDto>,
start_watcher: F,
) -> (
WorkspaceCancellation,
tokio::task::JoinHandle<anyhow::Result<WorkspaceStatus>>,
)
where
F: FnOnce(&mut WorkspaceDaemon) -> anyhow::Result<()> + Send + 'static,
{
let cancellation = WorkspaceCancellation::default();
let worker_cancellation = cancellation.clone();
let preload_span = telemetry::detached_operation_span("daemon.initial_preload");
Expand All @@ -226,8 +244,7 @@ fn spawn_initial_preload(
!worker_cancellation.is_cancelled(),
"workspace preload cancelled"
);
restart_live_watcher(&mut daemon)
.map_err(|error| anyhow::anyhow!(error.to_string()))?;
start_watcher(&mut daemon)?;
}
Ok(())
})();
Expand Down
2 changes: 1 addition & 1 deletion crates/daemon/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use crate::query::{
};
use crate::runtime::{
DaemonRpcService, generate_token, publish_current_snapshot, query_error,
workspace_unavailable_response,
spawn_initial_preload_with_watcher, workspace_unavailable_response,
};
use crate::source_sets::{
MemorySourceLimits, parse_memory_source_set, validate_memory_source_set_limits,
Expand Down
44 changes: 44 additions & 0 deletions crates/daemon/src/tests/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,50 @@ fn windows_supervisor_handle_child() {
std::thread::sleep(std::time::Duration::from_millis(250));
}

#[tokio::test(flavor = "multi_thread")]
async fn initial_preload_publishes_ready_before_live_watcher_can_block() {
let temp = tempfile::tempdir().expect("tempdir");
fs::write(temp.path().join("lib.rs"), "pub struct Indexed;\n").expect("write fixture");
let daemon = WorkspaceDaemon::new(vec![temp.path().to_path_buf()]).expect("daemon");
let daemon = Arc::new(Mutex::new(daemon));
let published = Arc::new(RwLock::new(None));
let lifecycle = Arc::new(RwLock::new(WorkspaceLifecycle::loading()));
let (events, _) = tokio::sync::broadcast::channel(8);
let (watcher_entered_tx, watcher_entered_rx) = std::sync::mpsc::channel();
let (release_watcher_tx, release_watcher_rx) = std::sync::mpsc::channel();

let (_, worker) = spawn_initial_preload_with_watcher(
daemon,
published.clone(),
lifecycle.clone(),
events,
move |_| {
watcher_entered_tx.send(()).expect("announce watcher start");
release_watcher_rx.recv().expect("release watcher start");
Ok(())
},
);
watcher_entered_rx
.recv_timeout(std::time::Duration::from_secs(10))
.expect("initial index reaches watcher startup");
let phase_while_watcher_is_blocked = lifecycle
.read()
.unwrap_or_else(|error| error.into_inner())
.phase;
let snapshot_published_while_watcher_is_blocked = published
.read()
.unwrap_or_else(|error| error.into_inner())
.is_some();
release_watcher_tx.send(()).expect("release watcher");
worker
.await
.expect("preload worker joins")
.expect("preload succeeds");

assert_eq!(phase_while_watcher_is_blocked, WorkspacePhase::Ready);
assert!(snapshot_published_while_watcher_is_blocked);
}

#[test]
fn daemon_token_is_128_bits_encoded_as_hex() {
let token = generate_token().expect("generate daemon token");
Expand Down
Loading