Fast startup: defer bootstrap to background, lazy feed load

- Node::open_with_bind no longer runs bootstrap (anchor connect, NAT
  probe, referrals). New run_bootstrap() method called from background
  task after UI is live.
- Background tasks (pull cycle, diff cycle, etc.) start after bootstrap
  completes, not during block_on.
- Feed no longer pre-loaded during welcome screen readiness check.
  Ready button enables immediately after get_node_info succeeds.
- Feed loads on tab switch, not during startup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Scott Reimers 2026-04-16 17:19:05 -04:00
parent 19a95b7c45
commit 5e7eed9638
3 changed files with 79 additions and 53 deletions

View file

@ -2464,33 +2464,43 @@ pub fn run() {
Arc::clone(mgr.active_node().expect("just created"))
};
// Start background networking
n.start_accept_loop();
n.start_pull_cycle(300);
n.start_diff_cycle(120);
n.start_rebalance_cycle(600);
n.start_growth_loop();
n.start_recovery_loop();
n.start_social_checkin_cycle(3600);
n.start_anchor_register_cycle(600);
n.start_upnp_renewal_cycle();
n.start_upnp_tcp_renewal_cycle();
n.start_http_server();
n.start_bootstrap_connectivity_check();
n.start_replication_cycle(600);
Ok::<_, anyhow::Error>((n, mgr))
})?;
// Start bootstrap + background tasks AFTER setup completes (non-blocking)
let boot_node = Arc::clone(&node);
let boot_data_dir = data_dir.clone();
tauri::async_runtime::spawn(async move {
// Bootstrap: connect to anchors, NAT probe, referrals (slow — runs in background)
if let Err(e) = boot_node.run_bootstrap(&boot_data_dir).await {
tracing::warn!(error = %e, "Background bootstrap failed");
}
// Start all background networking tasks
boot_node.start_accept_loop();
boot_node.start_pull_cycle(300);
boot_node.start_diff_cycle(120);
boot_node.start_rebalance_cycle(600);
boot_node.start_growth_loop();
boot_node.start_recovery_loop();
boot_node.start_social_checkin_cycle(3600);
boot_node.start_anchor_register_cycle(600);
boot_node.start_upnp_renewal_cycle();
boot_node.start_upnp_tcp_renewal_cycle();
boot_node.start_http_server();
boot_node.start_bootstrap_connectivity_check();
boot_node.start_replication_cycle(600);
let cache_max_bytes: u64 = {
let storage = n.storage.get().await;
let storage = boot_node.storage.get().await;
storage.get_setting("cache_size_bytes")
.ok()
.flatten()
.and_then(|s| s.parse().ok())
.unwrap_or(1_073_741_824u64)
};
Node::start_eviction_cycle(Arc::clone(&n), 300, cache_max_bytes);
Ok::<_, anyhow::Error>((n, mgr))
})?;
Node::start_eviction_cycle(Arc::clone(&boot_node), 300, cache_max_bytes);
});
// Manage both the swappable Node and the IdentityManager
let app_node: AppNode = Arc::new(tokio::sync::RwLock::new(node));